Skip to content
  1. Nov 22, 2024
  2. Nov 19, 2024
  3. Nov 15, 2024
    • Flavien BRIDAULT's avatar
      fix(ui): various fixes in the transfer function and image code · 7d3040d8
      Flavien BRIDAULT authored
      - move the PACS configuration in a module so that it can be used in other apps
      - the image is now an input and not an inout in the `module::ui::qt::image::window_level` service
      - adjust the range of `module::ui::qt::image::window_level` depending on the image range
      - remove the static label in the color widget of `module::ui::qt::settings`
      - `sight::data::helper::medical_image::get_min_max()` now returns its values as a pair to avoid a wrong initialisation in the caller code.
      - fix mixed rendering with binary transparent objects
      7d3040d8
    • Didier WECKMANN's avatar
      feat(core): add orientation attribute in image / image_series · c2d617b3
      Didier WECKMANN authored and Alexandre ANCEL's avatar Alexandre ANCEL committed
      - Add unit tests
      - Fix wrong return type in matrix4::position() and  matrix4::orientation()
      c2d617b3
  4. Nov 14, 2024
  5. Nov 13, 2024
  6. Nov 07, 2024
    • Marc SCHWEITZER's avatar
      enh(core): allow to call start/stop slots in updater · 9a2b1cef
      Marc SCHWEITZER authored
      Allow to call slot="start" or slot="stop" within an update_sequence.
      This ensure to call start/stop in a specific order.
      
      Example:
      
      
      ```xml
      <sequence uid="toggle_dev_mode">
          <service uid="video_grabber" slot="stop"/>
          <service uid="dummy_grabber" slot="start"/>
      </sequence>
      
      <sequence uid="toggle_prod_mode">
          <service uid="dummy_grabber" slot="stop"/>
          <service uid="video_grabber" slot="start"/>
      </sequence>
      ```
      9a2b1cef
  7. Nov 03, 2024
    • Flavien BRIDAULT's avatar
      misc: fix various bugs · cee3c950
      Flavien BRIDAULT authored
      - use malloc policy for images shared with ITK
      - send signals when action property is set
      - init text of combo box when using keys/values
      - do not autoconnect map properties to avoid spurious warnings when the service is used in an update loop
      - model_series adaptor was accidentally unregistered while updating
      - jobs::observer should not allow to report done work when finished
      cee3c950
  8. Oct 30, 2024
  9. Oct 21, 2024
  10. Oct 18, 2024
  11. Oct 17, 2024
  12. Oct 16, 2024
    • Flavien BRIDAULT's avatar
      enh(core): introduce explicit update loops · bb4bd72f
      Flavien BRIDAULT authored
      Chaining service updates in Sight live applications has always been tough. To circumvent all related issues with event-based chaining, we introduce an explicit approach allowing to specify update sequence and execute them all at once.
      
      It used to be possible to specify which services to update **once** once after start:
      
      ```xml
      <update uid="service1">
      <update uid="service2">
      <update uid="service3">
      ```
      
      This section is now modified and allows specifying these single-shot updates, but also the ability to define an update loop:
      
      ```xml
      <start uid="update_loop">
      
      <update>
           <service uid="service1"/>
           <service uid="service2"/>
           <sequence uid="update_loop" loop="true">
               <service uid="service3" />
               <service uid="service4" />
           </sequence>
      </update>
      ```
      
      In this example, `service1` and `service2` are updated once after start, while `service3` and `service4` are continuously updated. The sequence `update_loop`is identified with an uid, so it can be started and stopped like any other service. Doing this, the update sequence is not dependent on the updated() signal. This is much more robust because this means any other, maybe unwanted updates triggered from somewhere else do not affect the sequence.
      
      This new syntax also allows chaining update sequences between XML configurations. As the manner of UI registries and `wid`, it is possible to reserve a slot for another update sequence defined in another configuration:
      
      ```xml
      <!-- Main loop -->
      <update>
           <sequence uid="update_loop" loop="true">
               <service uid="service1" />
               <updater uid="sub_updater" />
               <service uid="service2" slot="modify" />
           </sequence>
      </update>
      
      <!-- In a sub-configuration, passing the parameter "sub_updater" -->
      <update>
           <sequence parent="${sub_updater}">
               <service uid="..." />
               <service uid="..." />
           </sequence>
      </update>
      ```
      
      Note that here the `uid` of the sequence is omitted because no interaction is required inside this XML. The sequence is played automatically by the root updater after `service1::update()` and `service2::modify` slots.
      
      It is also possible to execute services in parallel. Mixing sequences and parallel are allowed with the syntax:
      
      ```xml
      <!-- Main loop -->
      <update>
           <sequence uid="update_loop" loop="true">
               <service uid="service1" />
               <parallel>
                  <service uid="service2" />
                  <updater uid="sub_updater" />
                  <sequence>
                     <service uid="service3" />
                     <service uid="service4" />
                  </sequence>
               <parallel/>
               <service uid="service5" />
           </sequence>
      </update>
      
      <!-- In a sub-configuration, passing the parameter "sub_updater" -->
      <update>
           <sequence parent="${sub_updater}">
               <service uid="..." />
               <service uid="..." />
           </sequence>
      </update>
      ```
      
      In this example, `service1`updates first, then `service2`, the whole update sequence in the sub-configuration, and the sequence of `service3` and `service4` are executed in parallel. When they are executed, whether or not they are on different workers, `service5` is executed.
      
      The solution proposed above could be sufficient. However, managing `sight::viz::scene3d::render` could become tedious. Correctly using auto-connections, and maintaining the list of all adaptors in the update can be tedious and error-prone. Developers usually expect that a single call to the \`update()\` of the renderer manages the update of the adaptors properly, which is the case in auto mode when we do interactive rendering, but not in manual mode, in "live" applications.
      
      To solve this, we introduced a generic update interface `sight::core::updater` that will be inherited by the adaptors. This interface allows to defer the update of the adaptor required by their data. In manual mode, the adaptors just flag which part of their update process they should process. When the update is actually called, they will really perform it and unflag it. The render only requires to interrogate the adaptors before rendering to know if they need to update or not.
      
      To sum up, updating a generic scene in manual mode is now much easier and not error-prone regarding synchronisation. For example, if we imagine an application reading a video, extracting a feature and then display it in overlay over the video, the update loop could look like:
      
      ```xml
      <!-- Main loop -->
      <update>
           <sequence uid="main_loop" loop="true">
               <service uid="video_grabber_srv" />
               <service uid="extract_position_srv" />
               <service uid="compute_position_srv" />
               <service uid="render_srv" /> <!-- Update all adaptors, only those required if their data have changed -->
           </sequence>
      </update>
      ```
      bb4bd72f
  13. Oct 15, 2024
  14. Oct 14, 2024
    • Didier WECKMANN's avatar
      fix(test): sight_calibrator_uit frequent failures · 54eed3df
      Didier WECKMANN authored and Flavien BRIDAULT's avatar Flavien BRIDAULT committed
      Several fixes were brought:
      1. A Qt error was fixed when closing the chessboard window. This did not improve the situation but was needed anyway,
      2. The board square size was unintentionally set to 0.5 instead of 20 in !1138. This was, I think, the cause of the increase in the occurrence of the test failure, yielding values of around 180 or > 400.
      3. Sometimes, we still get cx=341 instead of 352. This might come from the input detection that slightly differs. We don't understand the reason, but since this is rather an issue of the test than an implementation error, we chose to increase the tolerance of the test to accept this value of 341.
      54eed3df
  15. Oct 11, 2024
  16. Oct 01, 2024
  17. Sep 30, 2024
    • Didier WECKMANN's avatar
      feat(core): logging rewrite · 1c15455f
      Didier WECKMANN authored and Didier WECKMANN's avatar Didier WECKMANN committed
      #### No separate `sight_log` process anymore
      
      Everything is self-contained in the current `sightrun` process. The logging is, by default in debug builds, in full synchronous mode, from end-to-end. In case of a crash, it is guaranteed to have everything sent to log to be readable back (with a possible, but improbable, loss of 16 bytes when encryption is used). However, since the full synchronous mode is blocking, there may be a significant performance hit, since the compression and the encryption are done in the same thread as the caller, which in turn, also block all other threads, if logging occurs during the writing. To overcome this, in release builds, I propose to use an asynchronous mode, which do the "real" writing in a separated thread (managed by boost::log). This is a bit less safe, but since RAII model is used, there is still a very good chance that everything is well written, even in case of fatal exception. And, to be honest, it was a bit the same level of safety with the previous separated process, as the stream communication between process was also buffered.
      
      >  zstd < 1.5 (for example, on ubuntu 22.04..) have a "flaw" that makes the block size to be "big", meaning we may loose a big chunk of data if interrupted (a block must be complete to be uncompressed). zstd >= 1.5 (like the one used in our VCPKG) ensure the "flush" command to complete a block, which is done on each log lines, ensuring we only "loose" the last lines. This explain why the associated unit test `crash_test` is somewhat "tolerant".
      
      > Of course we can discuss if we should be in asynchronous mode in release or always use the "safe" synchronous.
      
      #### No CMake `SIGHT_ENABLE_ENCRYPTED_LOG` anymore
      
      Log encryption is now enabled by `sightrun --encrypted-log` switch. However, the log will not be "really" encrypted, but only compressed, until a global password has been set, using, for example, the preferences dialog. See the `ex_acitivies` sample, especially the `CMakeLists.txt`, to learn how to ask a password from the user. As soon as the password is set or change and if the application has been started with `--encrypted-log` switch, a new log file "xxx.1.log.aes" will be created and the previous log "xxx.0.log.aes" will be relocated, recompressed and re-encrypted with the new password.
      
      #### No CMake `SIGHT_DEFAULT_PASSWORD` variable anymore
      
      SIGHT_DEFAULT_PASSWORD was used to pass a compile time "default" password, used to encrypt things without having to force the user to enter one. Even if the password was not stored in clear text in the binary, this was rather weak and confusing, so it has been removed. Consequently, there is no `password_keeper::has_default_password()` and `password_keeper::get_default_password()` have also been removed.
      
      #### spy_logger is no more only "global"
      
      You can now instantiate your own private logger using `spy_logger::make();`. The unit test `multiple_logger_test()` demonstrates the usage. You will not be able to use the sight macros (SIGHT_ERROR, ...) as they indeed use the global logger, but direct call to `spy_logger::error()`, `spy_logger::fatal()`, etc.
      
      The global spy_logger is now a global reference stored in `sight::core::log::g_logger`, available as soon as the `core` module is loaded.
      
      #### Archive_extractor now handles encrypted log
      
      A special extraction function `spy_logger::extract();` has been added, which is used in `sight::module::io::zip::extract` to manage our new log format. Since the logs are no more a plain zip file, and because we want to recover truncate files, third party tools like 7zip are no more able to decompress them. If there is only compression (empty password) used, then it should be readable by any tool that reads zstd compressed file.
      
      #### Unit tests improvement
      
      The logging tests have been rewritten and improved ...and fixed, as there were some race condition, left test materials, hang process, etc.. Almost 100% test coverage on the related files.
      
      #### General fixes and improvements
      
      - Now, we test the return values and error codes from OpenSSL encryption functions → yes, some "features" that were based on "bugs" were fixed.
      - Proper OpenSSL initialization, and error management
      - Split the spy_logger implementation in `libs\__\core\log\detail\spy_logger_impl.hxx` and `libs\__\core\log\detail\stream_sink.hxx`. The stream_sink.hxx implements a `boost/iostreams/stream` which can be used elsewhere to have an ostream with transparent zstd compression, with aes256 encryption.
      - Clang-tidy fixes on old files
      - proper guard for `#include <boost/iostreams/stream.hpp>` which generate a fatal warning on Windows
      - Some cleanup
      1c15455f
  18. Sep 27, 2024
  19. Sep 20, 2024
  20. Sep 19, 2024
  21. Sep 17, 2024
    • Flavien BRIDAULT's avatar
      feat(core): introduce properties in services · ff672b12
      Flavien BRIDAULT authored
      Services rely a lot on simple data such as algorithm parameters, using simple types such as
      numbers and strings. Manipulating these parameters always ends up requiring the same features:
      
      - initialization of the parameter in the XML configuration of the service,
      - dynamic update of the parameter through a slot,
      - persistence of the parameter during the runtime.
      
      To simplify the coding of these three features, we introduced the concept of service *properties*.
      
      For a complete description of this new exciting development feature, pleaser refer to
      https://sight.pages.ircad.fr/sight-doc/SAD/src/Properties.html
      ff672b12
  22. Sep 02, 2024
  23. Aug 20, 2024
    • Didier WECKMANN's avatar
      feat(core): add DICOM fields to manage source image · bc66d528
      Didier WECKMANN authored
      Add functions to DICOM API in `series` to manage DICOM `SourceImageSequence` which allows making `DERIVED` image (ex: a reconstructed volume derived from US frames sequence):
      - `[s|g]et_image_type()`: Sets/gets the `ImageType` of the series. The `ImageType`  is a `\` separated string with the following format: `[Pixel Data Characteristics:ORIGINAL|DERIVED], [Patient Examination Characteristics:PRIMARY|SECONDARY], [modality specific:xxx|yyy|...], [zzz], ...`: See ImageType (0008,0008) DICOM tag. The exact definition is modality dependent, but the two first elements ([ORIGINAL|DERIVED] and [PRIMARY|SECONDARY]) are fixed. This allows to set a reconstructed volume as `DERIVED` and the original frame sequence as `ORIGINAL` and, optionally, other attributes.
      - `[s|g]et_referenced_sop_class_uid()` and `[s|g]et_referenced_sop_instance_uid()`: Sets/gets the referenced series. Both are required for a valid DICOM.
      - Preliminary work to simplify the fiducials DICOM API: code factorization (more can be done like introducing high level fiducials functions in `has_fiducials`)
      bc66d528
  24. Jul 23, 2024
    • Evguenia SOBINE's avatar
      refactor(core): update and enhance ruler adaptor structure · 6fb49d49
      Evguenia SOBINE authored and Alexandre ANCEL's avatar Alexandre ANCEL committed
      - The usage of point_list has been removed. We now only use a vector of ogre elements and the associated ruler id. With this id, we can find the desired ruler in fiducials and modify or remove it.
      - The dashed line is now working correctly. 
      - Rulers should always be displayed according to the current slice. This includes rulers that have spheres on 2 different slices. If the current slice is in between, we will also display these rulers. The part of the line that is behind the current slice is displayed as a dashed line. This allows us to manage the ruler display the same for both 2D and 3D contexts.
       - Now we are registering the color of the ruler. By doing this, the indications on the slider will match the color of the ruler. We are also handling cases where rulers are created without color and outside of the adaptor. We register the assigned color by the adaptor during updating().
      - When we enter in interaction mode (activate_tool), we draw rulers with larger spheres. This makes it easier to grab the sphere when using a touch screen.
      - All deprecated services associated to old distance signals have been deleted.
      6fb49d49
  25. Jul 16, 2024
  26. Jul 13, 2024
  27. Jul 11, 2024
    • Flavien BRIDAULT's avatar
      enh(core): simplify passing objects as parameter in XML · 9aa7d5b9
      Flavien BRIDAULT authored
      We can now pass objects as parameters without declaring them locally with `src=ref`:
      
      ```xml
      <extension implements="sight::app::extension::config">
          <id>sight::module::config</id>
          <parameters>
              <object uid="image" type="sight::data::image" optional="true"
      />
              <object uid="model" type="sight::data::model_series" />
          </parameters>
          <config>
          ...
          </config>
      </extension>
      ```
      9aa7d5b9
  28. Jul 10, 2024
  29. Jul 09, 2024
  30. Jul 08, 2024
  31. Jul 04, 2024