Skip to content
  1. Jan 09, 2025
    • Flavien BRIDAULT's avatar
      refactor(geometry): modernize geometry libraries · a49f8358
      Flavien BRIDAULT authored
      Geometry libraries were refactored.
      - `sight::geometry::glm` becomes `sight::geometry`
      - `sight::geometry::data` now only contains functions relative to `sight::data` objects
      
      Several types were renamed or moved:
      
      * `fw_matrix4x4`: removed, replaced by `glm::dmat4`
      * `fw_plane`: replaced by `sight::geometry::plane_t`, moved all related code to `sight::geometry`
      * `fw_line`: redefined either by `sight::geometry::ray_t` or `sight::geometry::line_t` which both refers to `std::pair<glm::dvec3, glm::dvec3>`. Moved all related code to `sight::geometry`
      * `fw_vector_index` and `fw_vector_position`: all related code was removed
      
      Also `sight::data::image::world_to_image()` and `sight::data::image::image_to_world()` were moved from `sight::data` to `sight::geometry::data`.
      
      They were internally rewritten to be more "SIMD" friendly and new functions were added to get the raw transforms:
      - `sight::data::image::world_to_image_transform()`
      - `sight::data::image::image_to_world_transform()`
      
      This is especially useful in tight loops to avoid recomputing these matrices for each point/voxel.
      a49f8358
  2. Dec 19, 2024
    • Flavien BRIDAULT's avatar
      fix(viz): make material selector working again · 95c4bdbd
      Flavien BRIDAULT authored and Flavien BRIDAULT's avatar Flavien BRIDAULT committed
      95c4bdbd
    • Didier WECKMANN's avatar
      feat(core): image orientation support · ac1899b1
      Didier WECKMANN authored and Flavien BRIDAULT's avatar Flavien BRIDAULT committed
      This change ensures image orientation is used in filtering and visualisation.
      
      To help with the process and to factorize some code, the `sight::data::image` class now has two functions `data::image::image_to_world()` and `data::image::world_to_image()` that convert image coordinates from/to world coordinates. They use internally `data::image::m_orientation`, `data::image::m_origin` and `data::image::m_spacing` and they are templated, so you can use any container that holds 3d coordinates, without having to use `{x, y, z}` construct to convert from/to Ogre, ITK, ...
      
      Notable modified classes/helpers:
      
      - volume_renderer
      - ray_tracing_volume_renderer
      - scene
      - negato3d
      - negato2d
      - negato2d_camera
      - medical_image
      - plane
      - image_extruder
      - resampler
      - ITK (reader, writer, converter)
      - VTK (reader, writer, converter)
      - image_center
      - propagator
      - slice_index_position_editor
      - ruler
      - shape
      - point
      ac1899b1
  3. Dec 13, 2024
  4. Dec 12, 2024
  5. Dec 11, 2024
    • Flavien BRIDAULT's avatar
      enh(core): allow optional objects with defaults in configuration parameters · 934e5bbe
      Flavien BRIDAULT authored
      It is now possible to pass optional objects with default values in XML configurations:
      
      ```xml
      <extension implements="sight::app::extension::config">
          <id>...</id>
          <parameters>
              <!-- valid, if not passed, returns the object returned by the default constructor -->
              <object uid="model_series" type="sight::data::model_series" optional="true" />
      
              <!-- valid, if not passed, returns false -->
              <object uid="vr_visibility" type="sight::data::boolean" optional="true" value="false" />
      
              <!-- invalid because model_series is not a string_serializable -->
              <object uid="model_series" type="sight::data::model_series" optional="true" value="..." />
      
              <!-- invalid, "optional" must always be specified. -->
              <object uid="vr_visibility" type="sight::data::boolean" value="false" />
          </parameters>
      ...
      </extension>
      ```
      
      However, the keyword `optional` was already used before to pass deferred objects. To get something harmonized with local objects declaration, the `src` attribute is now deprecated and you must now use `deferred=true` at both places. Similarly, use `preference="true"` instead of `src="preference`.
      
      ```xml
      <extension implements="sight::app::extension::config">
          <id>...</id>
          <parameters>
              <!-- valid, if not passed, returns the object returned by the default constructor -->
              <object uid="model_series" type="sight::data::model_series" deferred="true" />
          </parameters>
          <config>
              <object uid="image" type="sight::data::image_series" deferred="true" />
              <object uid="bool" type="sight::data::boolean" value="true" preference="true" />
          </config>
      ...
      </extension>
      ```
      934e5bbe
    • Flavien BRIDAULT's avatar
      fix(ci): deploy doxygen and coverage in a single job · 2ec76144
      Flavien BRIDAULT authored
      The pages deployment must be done in a single job, otherwise they can delete each other content.
      2ec76144
  6. Dec 10, 2024
  7. Dec 09, 2024
    • Flavien BRIDAULT's avatar
      fix(core): improve handling of connection exceptions in proxies · 0aa06b77
      Flavien BRIDAULT authored
      Now, when an incompatibility is found between the signal and the slot, the exception is caught in the proxy and an error is returned. The config can still run, but it will not crash when closing.
      
      Also, an important bug was found when trying to match signal and slot signature. We can indeed omit part of the arguments of a signal when connecting a slot, but of course from the right. We can connect for instance:
      - (int, int) -> (int)
      - (int, int) -> ()
      
      But of course we refuse the inverse (we throw `sight::core::com::exception::bad_slot`):
      - (int) -> (int, int)
      - () -> (int, int)
      
      This mechanism works recursively but was broken when argument types were different like:
      - (int, int) -> (string)
      
      This led to a stack overflow. 😕 This is now fixed and throw `sight::core::com::exception::bad_slot` as well.
      0aa06b77
    • Flavien BRIDAULT's avatar
      fix(build): add CMake variables to specify vendor name and url for Qt and packaging · 5b1554eb
      Flavien BRIDAULT authored and Flavien BRIDAULT's avatar Flavien BRIDAULT committed
      Added variables SIGHT_APP_VENDOR and SIGHT_APP_VENDOR_URL, use them both for the QCoreApplication (runtime) and also for CPACK_PACKAGE_VENDOR (installer).
      5b1554eb
  8. Dec 06, 2024
  9. Dec 03, 2024
  10. Dec 02, 2024
  11. Nov 28, 2024
  12. Nov 25, 2024
    • Flavien BRIDAULT's avatar
      enh(core): simplify signal calls and blockers usage · 98e3486e
      Flavien BRIDAULT authored and Flavien BRIDAULT's avatar Flavien BRIDAULT committed
      ## Description
      
      The API to send a signal has been simplified for all data objects, including properties.
      
      Indeed the `sight::core::com::has_signals` interface brings four new functions:
      
      ```cpp
      
      template<typename ... A>
      void emit(const signals::signal_key_type& _key, A ... _a) const;
      
      template<typename ... A>
      void emit(com::has_slots* _caller, const signals::signal_key_type& _key, A ... _a) const;
      
      template<typename ... A>
      void async_emit(const signals::signal_key_type& _key, A ... _a) const;
      
      template<typename ... A>
      void async_emit(com::has_slots* _caller, const signals::signal_key_type& _key, A ... _a) const;
      ```
      
      They allow any signal holder to send a signal, synchronously or asynchronously, with a one-liner. The signature with a `com::has_slots` parameter allows to block all slots of the caller connected with the signal, preventing an infinite loop.
      
      Thus, instead of writing something like:
      
      ```cpp
      auto sig = object->signal<data::object::modified_signal_t>(data::object::MODIFIED_SIG);
      core::com::connection::blocker block(sig->get_connection(slot(service::slots::UPDATE)));
      sig->async_emit();
      ```
      
      You can call:
      ```
      object->async_emit(this, data::object::MODIFIED_SIG);
      ```
      
      Besides this major change, the XML configuration parser has been improved to ensure variables substitutions inside data containers.
      
      Example:
      
      ```xml
      <object uid="properties_map" type="sight::data::map">
          <item key="integer">
              <object uid="sub_object" type="sight::data::integer" value="45" />
          </item>
      </object>
      
      <service uid="..." type="example::service">
          <properties integer="${sub_object}" />
      </service>
      ```
      
      Before this merge-requests, the example service could not find the `sub_object` because the variable substitution was simply not performed.
      98e3486e
    • Flavien BRIDAULT's avatar
      0b3384c1
  13. Nov 22, 2024
  14. Nov 19, 2024
  15. 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
  16. Nov 14, 2024
  17. Nov 13, 2024
  18. 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
  19. 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
  20. Oct 30, 2024
  21. Oct 21, 2024
  22. Oct 18, 2024
  23. Oct 17, 2024
  24. 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
  25. Oct 15, 2024
Loading