diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000000..9c547f300a --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,99 @@ +# .git-blame-ignore-revs +# If you want this file to be utilised whener you utilise "git blame" on your local instance of the repository, +# run the following command from its root directory: +# git config blame.ignoreRevsFile .git-blame-ignore-revs + +9268f0874fc8b2c3af0a090b8084bd91707a115e +#Author: Daan Christiaens +#Date: Fri Dec 11 14:41:03 2015 +0100 +# Update copyright header in all source files, as discussed in #9 and #31. + +3024a116078eabd3b1353fc8329a73144632c86c +#Author: Thijs Dhollander +#Date: Thu Nov 22 17:01:59 2018 +1100 +# Copyright message update for next release (probably 2019-ish) +# Also updated the warranty statement: it appears this was still a formulation left over from the previous GPL license. The new formulation comes directly from the MPL 2.0, but is also more comprehensive; I'm more comfortable with having this more comprehensive. Furthermore, apart from it apparently being quite important to have a warranty statement at the top of source code files, it's apparently also of little value if it's not either very comprehensive, or it also directly refers to the license where the full text can be found. Hence, I added that as a sentence. +# Finally, also of note (and TODO) would be to add the copyright statement and a copy of the license somewhere on our (mrtrix.org) website. The final link is otherwise relatively useless in the context of the copyright and license statement. + +6c6c553ed9e9004ca8495ece436fec4db465d82b +#Author: Thijs Dhollander +#Date: Wed Dec 13 15:09:37 2017 +1100 +# Copyright update for upcoming RC which will probably end up around New Year's +# Also includes a change of mention of MRtrix to MRtrix3, in line with the phrase MRtrix3 developers, which was already in there/ +# Also includes removal of 2 .s, because they hindered clickability of the links in certain environments. + +654b7281c953f1068142d1f8a152f786862d8876 +#Author: Thijs Dhollander +#Date: Wed Jan 25 17:57:11 2017 +1100 +# header files + +b623e418e36de6884511d9c233b04392ecce89bb +#Author: Thijs Dhollander +#Date: Wed Jan 25 17:06:35 2017 +1100 +# Copyright for 2017 in headers + +95b144df3d9eb837fae08129cc292c3fb8490eac +#Author: Robert Smith +#Date: Tue Oct 8 14:33:10 2019 +1100 +# Add copyright notice to non-CPP files +# Also includes some line ending conversions and indentation changes. + +be9a46286a9053fd1c1951fe5394206a95b61bfa +#Author: MRtrixBot +#Date: Thu May 14 11:30:13 2020 +1000 +# Initial commit of "update_copyright" changes + +5e3112eae6ba4027aba854b3385f032c67dbfedf +#Author: MRtrixBot +#Date: Mon Feb 7 16:48:14 2022 +0000 +# update copyright notice and corresponding docs + +e8edf6d946822c8ec23d077c2b1e9eef471b2539 +#Author: MRtrixBot +#Date: Tue Jan 3 13:41:40 2023 +0100 +# Update copyright notice + +74ff7cf0b76e2c9595b1341a7e4a49fa5491ce2f +#Author: MRtrixBot +#Date: Wed Jan 6 12:50:54 2021 +0000 +# Update copyright notice + +65b3ea5e549f3f66a9e3c5d9ebdabb2a9bb462b4 +#Author: Thijs Dhollander +#Date: Thu Nov 22 17:30:36 2018 +1100 +# Fixed typo in copyright/warranty statement. + +729dd6cfc1a773f0f16592b8533c6e9d89d03ac3 +#Author: Thijs Dhollander +#Date: Mon May 15 10:33:05 2017 +1000 +# copyright update and cleanup + +76ad4fbb3ea60ea56ec94e3debfce1b7a35a9535 +#Author: rtabbara +#Date: Thu Feb 18 11:55:53 2016 +1100 +# User docs: Update commands list with new copyright + +6552f6ebe4f9fda441255063230ef9f8d9912591 +#Author: J-Donald Tournier +#Date: Wed Feb 5 12:50:53 2020 +0000 +# remove carriage returns + +811361d3af3ecfec03e20c2ee0f342634810a9c2 +#Author: Thijs Dhollander +#Date: Tue May 9 09:09:51 2017 +1000 +# docs update + +1eb36099870a0fffbc307ac40523dd8b6e35436f +#Author: Thijs Dhollander +#Date: Thu Feb 2 12:26:20 2017 +1100 +# standardise number of blank lines between copyright header and the rest of a file (was getting a bit out of hand for some files; now it's 2 blank lines for all) + +e8edf6d946822c8ec23d077c2b1e9eef471b2539 +#Author: MRtrixBot +#Date: Tue Jan 3 13:41:40 2023 +0100 +# Update copyright notice + +aad44d847ac48d02bb7f8badf801dbfaa0ccdac0 +#Author: MRtrixBot +#Date: Tue Jan 3 13:42:58 2023 +0100 +# Update Copyright notice in command docs diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index e737c30f59..96d437d03f 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -3,9 +3,11 @@ name: checks on: pull_request: types: [opened, synchronize] - branches: - - master - - dev + branches: [ master, dev ] + merge_group: + types: [checks_requested] + branches: [ master ] + diff --git a/core/app.cpp b/core/app.cpp index 0561070797..d6c526597f 100644 --- a/core/app.cpp +++ b/core/app.cpp @@ -128,7 +128,7 @@ namespace MR inline void get_matches (vector& candidates, const OptionGroup& group, const std::string& stub) { for (size_t i = 0; i < group.size(); ++i) { - if (stub.compare (0, stub.size(), group[i].id, stub.size()) == 0) + if (stub.compare (0, stub.size(), std::string(group[i].id), 0, stub.size()) == 0) candidates.push_back (&group[i]); } } diff --git a/src/dwi/tractography/SIFT2/tckfactor.cpp b/src/dwi/tractography/SIFT2/tckfactor.cpp index bb8a65010d..25f56b4cd9 100644 --- a/src/dwi/tractography/SIFT2/tckfactor.cpp +++ b/src/dwi/tractography/SIFT2/tckfactor.cpp @@ -374,19 +374,22 @@ namespace MR { { if (size_t(coefficients.size()) != contributions.size()) throw Exception ("Cannot output weighting factors if they have not first been estimated!"); + decltype(coefficients) weights; try { - decltype(coefficients) weights (coefficients.size()); - for (SIFT::track_t i = 0; i != num_tracks(); ++i) - weights[i] = (coefficients[i] == min_coeff || !std::isfinite(coefficients[i])) ? - 0.0 : - std::exp (coefficients[i]); - save_vector (weights, path); + weights.resize (coefficients.size()); } catch (...) { WARN ("Unable to assign memory for output factor file: \"" + Path::basename(path) + "\" not created"); + return; } + for (SIFT::track_t i = 0; i != num_tracks(); ++i) + weights[i] = (coefficients[i] == min_coeff || !std::isfinite(coefficients[i])) ? + 0.0 : + std::exp (coefficients[i]); + save_vector (weights, path); } + void TckFactor::output_coefficients (const std::string& path) const { save_vector (coefficients, path); diff --git a/src/gui/mrview/colourmap_button.cpp b/src/gui/mrview/colourmap_button.cpp index 14988cf309..55f76ede94 100644 --- a/src/gui/mrview/colourmap_button.cpp +++ b/src/gui/mrview/colourmap_button.cpp @@ -118,10 +118,10 @@ void ColourMapButton::init_special_colour_menu_items(bool create_shortcuts) void ColourMapButton::init_customise_state_menu_items() { - auto show_colour_bar = colourmap_menu->addAction(tr("Show colour bar"), this, SLOT(show_colour_bar_slot(bool))); - show_colour_bar->setCheckable(true); - show_colour_bar->setChecked(true); - addAction(show_colour_bar); + show_colour_bar_action = colourmap_menu->addAction(tr("Show colour bar"), this, SLOT(show_colour_bar_slot(bool))); + show_colour_bar_action->setCheckable(true); + show_colour_bar_action->setChecked(true); + addAction(show_colour_bar_action); invert_scale_action = colourmap_menu->addAction(tr("Invert"), this, SLOT(invert_colourmap_slot(bool))); invert_scale_action->setCheckable(true); @@ -163,12 +163,18 @@ void ColourMapButton::set_colourmap_index(size_t index) } } -void ColourMapButton::set_scale_inverted(bool yesno) +void ColourMapButton::set_scale_inverted (bool yesno) { assert (invert_scale_action != nullptr); invert_scale_action->setChecked (yesno); } +void ColourMapButton::set_show_colourbar (bool yesno) +{ + assert (invert_scale_action != nullptr); + show_colour_bar_action->setChecked (yesno); +} + void ColourMapButton::set_fixed_colour() { diff --git a/src/gui/mrview/colourmap_button.h b/src/gui/mrview/colourmap_button.h index 8a66086c6d..9491d625da 100644 --- a/src/gui/mrview/colourmap_button.h +++ b/src/gui/mrview/colourmap_button.h @@ -34,11 +34,11 @@ class ColourMapButton; class ColourMapButtonObserver { public: - virtual void selected_colourmap(size_t, const ColourMapButton&) {} - virtual void selected_custom_colour(const QColor&, const ColourMapButton&) {} - virtual void toggle_show_colour_bar(bool, const ColourMapButton&) {} - virtual void toggle_invert_colourmap(bool, const ColourMapButton&) {} - virtual void reset_colourmap(const ColourMapButton&) {} + virtual void selected_colourmap (size_t, const ColourMapButton&) {} + virtual void selected_custom_colour (const QColor&, const ColourMapButton&) {} + virtual void toggle_show_colour_bar (bool, const ColourMapButton&) {} + virtual void toggle_invert_colourmap (bool, const ColourMapButton&) {} + virtual void reset_colourmap (const ColourMapButton&) {} }; @@ -46,12 +46,13 @@ class ColourMapButton : public QToolButton { Q_OBJECT public: - ColourMapButton(QWidget* parent, ColourMapButtonObserver& obs, + ColourMapButton (QWidget* parent, ColourMapButtonObserver& obs, bool use_shortcuts = false, bool use_special_colourmaps = true, bool use_customise_state_items = true); - void set_colourmap_index(size_t index); - void set_scale_inverted(bool yesno); + void set_colourmap_index (size_t index); + void set_scale_inverted (bool yesno); + void set_show_colourbar (bool yesno); void set_fixed_colour(); vector colourmap_actions; void open_menu (const QPoint& p) { colourmap_menu->exec (p); } @@ -71,6 +72,7 @@ class ColourMapButton : public QToolButton QMenu* colourmap_menu; QAction* custom_colour_action; QAction* invert_scale_action; + QAction* show_colour_bar_action; size_t fixed_colour_index; diff --git a/src/gui/mrview/colourmap_menu.cpp b/src/gui/mrview/colourmap_menu.cpp deleted file mode 100644 index 814d4b8ce0..0000000000 --- a/src/gui/mrview/colourmap_menu.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* Copyright (c) 2008-2023 the MRtrix3 contributors. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Covered Software is provided under this License on an "as is" - * basis, without warranty of any kind, either expressed, implied, or - * statutory, including, without limitation, warranties that the - * Covered Software is free of defects, merchantable, fit for a - * particular purpose or non-infringing. - * See the Mozilla Public License v. 2.0 for more details. - * - * For more details, see http://www.mrtrix.org/. - */ - -#include "gui/gui.h" -#include "gui/mrview/colourmap_menu.h" - -namespace MR -{ - namespace GUI - { - namespace MRView - { - - - - void create_colourmap_menu (QWidget* parent, QActionGroup*& group, - QMenu* menu, QAction** & actions, - bool create_shortcuts, bool use_special) - { - group = new QActionGroup (parent); - group->setExclusive (true); - actions = new QAction* [ColourMap::num()]; - bool in_scalar_section = true; - - for (size_t n = 0; ColourMap::maps[n].name; ++n) { - if (ColourMap::maps[n].special && !use_special) - continue; - QAction* action = new QAction (ColourMap::maps[n].name, parent); - action->setCheckable (true); - group->addAction (action); - - if (ColourMap::maps[n].special && in_scalar_section) { - menu->addSeparator(); - in_scalar_section = false; - } - - menu->addAction (action); - parent->addAction (action); - - if (create_shortcuts) - action->setShortcut (qstr ("Ctrl+" + str (n+1))); - - actions[n] = action; - } - - actions[0]->setChecked (true); - } - - - - } - } -} - diff --git a/src/gui/mrview/colourmap_menu.h b/src/gui/mrview/colourmap_menu.h deleted file mode 100644 index 3fe4d16b34..0000000000 --- a/src/gui/mrview/colourmap_menu.h +++ /dev/null @@ -1,49 +0,0 @@ -/* Copyright (c) 2008-2023 the MRtrix3 contributors. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Covered Software is provided under this License on an "as is" - * basis, without warranty of any kind, either expressed, implied, or - * statutory, including, without limitation, warranties that the - * Covered Software is free of defects, merchantable, fit for a - * particular purpose or non-infringing. - * See the Mozilla Public License v. 2.0 for more details. - * - * For more details, see http://www.mrtrix.org/. - */ - -#ifndef __gui_mrview_colourmap_menu_h__ -#define __gui_mrview_colourmap_menu_h__ - -#include "colourmap.h" -#include "gui/opengl/gl.h" - -namespace MR -{ - namespace GUI - { - namespace MRView - { - - - - void create_colourmap_menu (QWidget* parent, - QActionGroup*& group, - QMenu* menu, - QAction** & actions, - bool create_shortcuts = false, - bool use_special = true); - - - - } - } -} - -#endif - - - - diff --git a/src/gui/mrview/displayable.h b/src/gui/mrview/displayable.h index fd3c2c5cd9..aa3d1838c3 100644 --- a/src/gui/mrview/displayable.h +++ b/src/gui/mrview/displayable.h @@ -138,10 +138,16 @@ namespace MR flags_ = cmap; } - void set_colour (std::array &c) { + void set_colour (const std::array &c) { colour = c; } + void set_colour (const QColor &c) { + colour[0] = c.red(); + colour[1] = c.green(); + colour[2] = c.blue(); + } + void set_use_discard_lower (bool yesno) { if (!discard_lower_enabled()) return; set_bit (DiscardLower, yesno); diff --git a/src/gui/mrview/tool/overlay.cpp b/src/gui/mrview/tool/overlay.cpp index 3cb332b532..05326ed989 100644 --- a/src/gui/mrview/tool/overlay.cpp +++ b/src/gui/mrview/tool/overlay.cpp @@ -631,7 +631,7 @@ namespace MR if (colourmap_index == -2) colourmap_index = overlay->colourmap; else - colourmap_index = -1; + colourmap_index = -1; } num_inverted += overlay->scale_inverted(); rate += overlay->scaling_rate(); diff --git a/src/gui/mrview/tool/tractography/track_scalar_file.cpp b/src/gui/mrview/tool/tractography/track_scalar_file.cpp index dad1f5a948..701ca0c108 100644 --- a/src/gui/mrview/tool/tractography/track_scalar_file.cpp +++ b/src/gui/mrview/tool/tractography/track_scalar_file.cpp @@ -17,7 +17,6 @@ #include "gui/mrview/tool/tractography/track_scalar_file.h" #include "gui/dialog/file.h" -#include "gui/mrview/colourmap_menu.h" #include "gui/mrview/tool/tractography/tractogram.h" @@ -52,34 +51,7 @@ namespace MR connect (intensity_file_button, SIGNAL (clicked()), this, SLOT (open_intensity_track_scalar_file_slot ())); hlayout->addWidget (intensity_file_button); - // Colourmap menu: - colourmap_menu = new QMenu (tr ("Colourmap menu"), this); - - MRView::create_colourmap_menu (this, colourmap_group, colourmap_menu, colourmap_actions, false, false); - connect (colourmap_group, SIGNAL (triggered (QAction*)), this, SLOT (select_colourmap_slot())); - colourmap_actions[1]->setChecked (true); - - colourmap_menu->addSeparator(); - - show_colour_bar = colourmap_menu->addAction (tr ("Show colour bar"), this, SLOT (show_colour_bar_slot())); - show_colour_bar->setCheckable (true); - show_colour_bar->setChecked (true); - addAction (show_colour_bar); - - invert_scale = colourmap_menu->addAction (tr ("Invert"), this, SLOT (invert_colourmap_slot())); - invert_scale->setCheckable (true); - addAction (invert_scale); - - colourmap_menu->addSeparator(); - - QAction* reset_intensity = colourmap_menu->addAction (tr ("Reset intensity"), this, SLOT (reset_intensity_slot())); - addAction (reset_intensity); - - colourmap_button = new QToolButton (this); - colourmap_button->setToolTip (tr ("Colourmap menu")); - colourmap_button->setIcon (QIcon (":/colourmap.svg")); - colourmap_button->setPopupMode (QToolButton::InstantPopup); - colourmap_button->setMenu (colourmap_menu); + colourmap_button = new ColourMapButton(this, *this, false, false, true); hlayout->addWidget (colourmap_button); vlayout->addLayout (hlayout); @@ -159,7 +131,8 @@ namespace MR window().colourbar_renderer.render (tractogram.colourmap, tractogram.scale_inverted(), min_value, max_value, - tractogram.scaling_min(), tractogram.display_range, tractogram.colour); + tractogram.scaling_min(), tractogram.display_range, + { tractogram.colour[0]/255.0f, tractogram.colour[1]/255.0f, tractogram.colour[2]/255.0f }); } @@ -180,10 +153,10 @@ namespace MR min_entry->setValue (tractogram->scaling_min()); max_entry->setValue (tractogram->scaling_max()); - colourmap_menu->setEnabled (true); - colourmap_actions[tractogram->colourmap]->setChecked (true); - show_colour_bar->setChecked (tractogram->show_colour_bar); - invert_scale->setChecked (tractogram->scale_inverted()); + colourmap_button->setEnabled (true); + colourmap_button->set_colourmap_index(tractogram->colourmap); + colourmap_button->set_scale_inverted (tractogram->scale_inverted()); + colourmap_button->set_show_colourbar (tractogram->show_colour_bar); assert (tractogram->intensity_scalar_filename.length()); intensity_file_button->setText (qstr (shorten (Path::basename (tractogram->intensity_scalar_filename), 35, 0))); @@ -259,28 +232,30 @@ namespace MR return scalar_file.size(); } - void TrackScalarFileOptions::show_colour_bar_slot () + void TrackScalarFileOptions::toggle_show_colour_bar(bool show_colour_bar, const ColourMapButton&) { if (tractogram) { - tractogram->show_colour_bar = show_colour_bar->isChecked(); + tractogram->show_colour_bar = show_colour_bar; window().updateGL(); } } - void TrackScalarFileOptions::select_colourmap_slot () + void TrackScalarFileOptions::selected_colourmap (size_t cmap, const ColourMapButton&) { if (tractogram) { - QAction* action = colourmap_group->checkedAction(); - size_t n = 0; - while (action != colourmap_actions[n]) - ++n; - tractogram->colourmap = n; + tractogram->colourmap = cmap; window().updateGL(); } } - + void TrackScalarFileOptions::selected_custom_colour (const QColor& c, const ColourMapButton&) + { + if (tractogram) { + tractogram->set_colour (c); + window().updateGL(); + } + } void TrackScalarFileOptions::set_threshold(GUI::MRView::Tool::TrackThresholdType dataSource, default_type min, default_type max)//TrackThresholdType dataSource { @@ -429,7 +404,7 @@ namespace MR } - void TrackScalarFileOptions::reset_intensity_slot () + void TrackScalarFileOptions::reset_colourmap (const ColourMapButton&) { if (tractogram) { tractogram->reset_windowing(); @@ -439,19 +414,10 @@ namespace MR } - void TrackScalarFileOptions::invert_colourmap_slot () + void TrackScalarFileOptions::toggle_invert_colourmap (bool invert, const ColourMapButton&) { if (tractogram) { - tractogram->set_invert_scale (invert_scale->isChecked()); - window().updateGL(); - } - } - - void TrackScalarFileOptions::set_colourmap (int colourmap_index) - { - if (tractogram) { - tractogram->colourmap = colourmap_index; - update_UI(); + tractogram->set_invert_scale (invert); window().updateGL(); } } diff --git a/src/gui/mrview/tool/tractography/track_scalar_file.h b/src/gui/mrview/tool/tractography/track_scalar_file.h index 3de3f57e9c..9aade44f45 100644 --- a/src/gui/mrview/tool/tractography/track_scalar_file.h +++ b/src/gui/mrview/tool/tractography/track_scalar_file.h @@ -18,6 +18,7 @@ #define __gui_mrtrix_tools_tractography_scalar_file_options_h__ #include "gui/mrview/adjust_button.h" +#include "gui/mrview/colourmap_button.h" #include "gui/mrview/displayable.h" #include "gui/mrview/tool/base.h" #include "gui/mrview/tool/tractography/tractogram_enums.h" @@ -36,8 +37,10 @@ namespace MR class Tractogram; class Tractography; - class TrackScalarFileOptions : public QGroupBox, public DisplayableVisitor - { + + + class TrackScalarFileOptions : public QGroupBox, public ColourMapButtonObserver, public DisplayableVisitor + { Q_OBJECT public: @@ -51,7 +54,13 @@ namespace MR void update_UI(); void set_scaling(default_type min, default_type max); void set_threshold(GUI::MRView::Tool::TrackThresholdType dataSource, default_type min, default_type max); - void set_colourmap (int colourmap_index); + void set_colourmap (int colourmap_index) { colourmap_button->set_colourmap_index (colourmap_index); } + + void selected_colourmap (size_t, const ColourMapButton&) override; + void selected_custom_colour (const QColor&, const ColourMapButton&) override; + void toggle_show_colour_bar (bool, const ColourMapButton&) override; + void toggle_invert_colourmap (bool, const ColourMapButton&) override; + void reset_colourmap (const ColourMapButton&) override; public slots: bool open_intensity_track_scalar_file_slot (); @@ -59,17 +68,13 @@ namespace MR private slots: - void show_colour_bar_slot(); - void select_colourmap_slot (); void on_set_scaling_slot (); bool threshold_scalar_file_slot (int); void threshold_lower_changed (int unused); void threshold_upper_changed (int unused); void threshold_lower_value_changed (); void threshold_upper_value_changed (); - void invert_colourmap_slot (); - void reset_intensity_slot (); - + protected: Tractography* tool; @@ -78,10 +83,7 @@ namespace MR QGroupBox *colour_groupbox; QAction *show_colour_bar; QAction *invert_scale; - QMenu *colourmap_menu; - QAction **colourmap_actions; - QActionGroup *colourmap_group; - QToolButton *colourmap_button; + ColourMapButton* colourmap_button; QPushButton *intensity_file_button; AdjustButton *max_entry, *min_entry; QComboBox *threshold_file_combobox; diff --git a/src/gui/mrview/tool/tractography/tractogram.cpp b/src/gui/mrview/tool/tractography/tractogram.cpp index 5749e542a7..54fe44c22e 100644 --- a/src/gui/mrview/tool/tractography/tractogram.cpp +++ b/src/gui/mrview/tool/tractography/tractogram.cpp @@ -67,6 +67,7 @@ namespace MR "uniform float slab_width;\n" "uniform float offset, scale;\n" "uniform float scale_x, scale_y;\n" + "uniform vec3 colourmap_colour;\n" "out vec3 v_tangent;\n" "out vec2 v_end;\n"; @@ -220,7 +221,7 @@ namespace MR std::string source = "uniform float lower, upper;\n" - "uniform vec3 const_colour;\n" + "uniform vec3 colourmap_colour;\n" "uniform mat4 MV;\n" "out vec3 colour;\n"; @@ -282,7 +283,7 @@ namespace MR : " colour = v_colour;\n"; break; case TrackColourType::Manual: - source += " colour = const_colour;\n"; + source += " colour = colourmap_colour;\n"; } if (use_lighting && (using_geom || using_points)) { @@ -429,7 +430,8 @@ namespace MR } if (color_type == TrackColourType::Manual) - gl::Uniform3fv (gl::GetUniformLocation (track_shader, "const_colour"), 1, colour.data()); + gl::Uniform3f (gl::GetUniformLocation (track_shader, "colourmap_colour"), + colour[0]/255.0, colour[1]/255.0, colour[2]/255.0); if (color_type == TrackColourType::ScalarFile) { gl::Uniform1f (gl::GetUniformLocation (track_shader, "offset"), display_midpoint - 0.5f * display_range); diff --git a/src/gui/mrview/tool/tractography/tractogram.h b/src/gui/mrview/tool/tractography/tractogram.h index 3553d0e865..90253c1b28 100644 --- a/src/gui/mrview/tool/tractography/tractogram.h +++ b/src/gui/mrview/tool/tractography/tractogram.h @@ -69,8 +69,6 @@ namespace MR TrackThresholdType get_threshold_type() const { return threshold_type; } TrackGeometryType get_geometry_type() const { return geometry_type; } - void set_colour (float c[3]) { colour = { c[0], c[1], c[2] }; } - float get_threshold_rate() const { switch (threshold_type) { case TrackThresholdType::None: return NaN; @@ -90,7 +88,6 @@ namespace MR bool scalarfile_by_direction; bool show_colour_bar; bool should_update_stride; - Eigen::Array3f colour; float original_fov; float line_thickness; std::string intensity_scalar_filename; diff --git a/src/gui/mrview/tool/tractography/tractography.cpp b/src/gui/mrview/tool/tractography/tractography.cpp index a00ab7a0ee..ed7b6e9e4e 100644 --- a/src/gui/mrview/tool/tractography/tractography.cpp +++ b/src/gui/mrview/tool/tractography/tractography.cpp @@ -564,11 +564,12 @@ namespace MR colour[2] = rng(); } while (colour[0] < 0.5 && colour[1] < 0.5 && colour[2] < 0.5); tractogram->set_color_type (TrackColourType::Manual); - tractogram->set_colour (colour); + QColor c (colour[0]*255.0f, colour[1]*255.0f, colour[2]*255.0f); + tractogram->set_colour (c); if (tractogram->get_threshold_type() == TrackThresholdType::UseColourFile) tractogram->set_threshold_type (TrackThresholdType::None); if (!i) - colour_button->setColor (QColor (colour[0]*255.0f, colour[1]*255.0f, colour[2]*255.0f)); + colour_button->setColor (c); } colour_combobox->blockSignals (true); colour_combobox->setCurrentIndex (2); @@ -584,13 +585,12 @@ namespace MR { QColor color; color = QColorDialog::getColor(Qt::red, this, "Select Color", QColorDialog::DontUseNativeDialog); - float colour[] = {float(color.redF()), float(color.greenF()), float(color.blueF())}; if (color.isValid()) { QModelIndexList indices = tractogram_list_view->selectionModel()->selectedIndexes(); for (int i = 0; i < indices.size(); ++i) { Tractogram* tractogram = tractogram_list_model->get_tractogram (indices[i]); tractogram->set_color_type (TrackColourType::Manual); - tractogram->set_colour (colour); + tractogram->set_colour (color); if (tractogram->get_threshold_type() == TrackThresholdType::UseColourFile) tractogram->set_threshold_type (TrackThresholdType::None); } @@ -599,7 +599,7 @@ namespace MR colour_combobox->clearError(); colour_combobox->blockSignals (false); colour_button->setEnabled (true); - colour_button->setColor (QColor (colour[0]*255.0f, colour[1]*255.0f, colour[2]*255.0f)); + colour_button->setColor (color); update_scalar_options(); } window().updateGL(); @@ -668,9 +668,8 @@ namespace MR const QColor color = colour_button->color(); if (color.isValid()) { QModelIndexList indices = tractogram_list_view->selectionModel()->selectedIndexes(); - float c[3] = { color.red()/255.0f, color.green()/255.0f, color.blue()/255.0f }; for (int i = 0; i < indices.size(); ++i) - tractogram_list_model->get_tractogram (indices[i])->set_colour (c); + tractogram_list_model->get_tractogram (indices[i])->set_colour (color); colour_combobox->blockSignals (true); colour_combobox->setCurrentIndex (3); // In case it was on random colour_combobox->clearError(); @@ -717,7 +716,7 @@ namespace MR const Tractogram* first_tractogram = tractogram_list_model->get_tractogram (indices[0]); TrackColourType color_type = first_tractogram->get_color_type(); - Eigen::Array3f color = first_tractogram->colour; + QColor color (first_tractogram->colour[0], first_tractogram->colour[1], first_tractogram->colour[2]); TrackGeometryType geom_type = first_tractogram->get_geometry_type(); bool color_type_consistent = true, geometry_type_consistent = true; float mean_thickness = first_tractogram->line_thickness; @@ -743,7 +742,7 @@ namespace MR case TrackColourType::Manual: colour_combobox->setCurrentIndex (3); colour_button->setEnabled (true); - colour_button->setColor (QColor (color[0]*255.0f, color[1]*255.0f, color[2]*255.0f)); + colour_button->setColor (color); break; case TrackColourType::ScalarFile: colour_combobox->setCurrentIndex (4); @@ -988,16 +987,10 @@ namespace MR const float max_value = std::max ({ values[0], values[1], values[2] }); if (std::min ({ values[0], values[1], values[2] }) < 0.0 || max_value > 255) throw Exception ("values provided to -tractogram.colour must be either between 0.0 and 1.0, or between 0 and 255"); - const float multiplier = max_value <= 1.0 ? 1.0 : 1.0/255.0; + const float multiplier = max_value <= 1.0 ? 255.0 : 1.0; //input need to be a float * - float colour_input[3] = { - multiplier * float (values[0]), - multiplier * float (values[1]), - multiplier * float (values[2]) - }; - - QColor colour (int(values[0]*255.0), int(values[1]*255.0), int(values[2]*255.0)); + QColor colour (multiplier*values[0], multiplier*values[1], multiplier*values[2]); QModelIndexList indices = tractogram_list_view->selectionModel()->selectedIndexes(); @@ -1008,7 +1001,7 @@ namespace MR // set the color tractogram->set_color_type (TrackColourType::Manual); - tractogram->set_colour (colour_input); + tractogram->set_colour (colour); // update_color_type_gui colour_combobox->setCurrentIndex (3); diff --git a/src/surface/mesh.cpp b/src/surface/mesh.cpp index ded80cf58e..a86a1b0bbc 100644 --- a/src/surface/mesh.cpp +++ b/src/surface/mesh.cpp @@ -92,6 +92,20 @@ namespace MR + namespace { + template + void load_vtk_points_binary (std::ifstream& in, const size_t num_vertices, vector>& out) + { + out.reserve (num_vertices); + Eigen::Matrix v; + for (size_t i = 0; i != num_vertices; ++i) { + in.read (reinterpret_cast(v.data()), 3 * sizeof (T)); + out.push_back (v); + } + } + } + + void Mesh::load_vtk (const std::string& path) { @@ -129,6 +143,13 @@ namespace MR if (line == "STRUCTURED_POINTS" || line == "STRUCTURED_GRID" || line == "UNSTRUCTURED_GRID" || line == "RECTILINEAR_GRID" || line == "FIELD") throw Exception ("Unsupported dataset type (" + line + ") in .vtk file"); + // Won't know endianness of file when the vertex positions are read, + // only when the polygon information is encountered; + bool change_endianness = false; + + // If both float and big-endian, need to store natively as floats and swap endianness later + vector> vertices_float; + // From here, don't necessarily know which parts of the data will come first while (!in.eof()) { @@ -159,25 +180,20 @@ namespace MR throw Exception ("Error in reading binary .vtk file: Unsupported datatype (\"" + line + "\""); vertices.reserve (num_vertices); - for (int i = 0; i != num_vertices; ++i) { + if (!is_double) + vertices_float.reserve (num_vertices); + Vertex v; - Vertex v; - if (is_ascii) { + if (is_ascii) { + for (int i = 0; i != num_vertices; ++i) { MR::getline (in, line); sscanf (line.c_str(), "%lf %lf %lf", &v[0], &v[1], &v[2]); - } else { - if (is_double) { - double data[3]; - in.read (reinterpret_cast(&data[0]), 3 * sizeof (double)); - v = { data[0], data[1], data[2] }; - } else { - float data[3]; - in.read (reinterpret_cast(&data[0]), 3 * sizeof (float)); - v = { data[0], data[1], data[2] }; - } + vertices.push_back (v); } - vertices.push_back (v); - + } else if (is_double) { + load_vtk_points_binary (in, num_vertices, vertices); + } else { + load_vtk_points_binary (in, num_vertices, vertices_float); } } else if (line.substr (0, 8) == "POLYGONS") { @@ -199,8 +215,16 @@ namespace MR in.read (reinterpret_cast(&vertex_count), sizeof (int)); } + if (!is_ascii) { + if (change_endianness) { + vertex_count = ByteOrder::swap (vertex_count); + } else if (vertex_count != 3 && vertex_count != 4) { + vertex_count = ByteOrder::swap (vertex_count); + change_endianness = true; + } + } if (vertex_count != 3 && vertex_count != 4) - throw Exception ("Could not parse file \"" + path + "\"; only suppport 3- and 4-vertex polygons"); + throw Exception ("Could not parse file \"" + path + "\": only support 3- and 4-vertex polygons"); vector t (vertex_count, 0); @@ -230,17 +254,52 @@ namespace MR } } - // TODO If reading a binary file, may want to test endianness of data - // There's no explicit flag for this, but just calculating the standard - // deviations of all vertex positions may be adequate - // (likely to be huge if the endianness is wrong) - // Alternatively, just test the polygon indices: if there's at least one that exceeds the - // number of vertices, it may be saved in big-endian format, so try flipping everything - // Actually, should pop up at the first polygon read: number of points in polygon won't be 3 or 4 + if (!is_ascii) { +#if MRTRIX_IS_BIG_ENDIAN + if (change_endianness) { + WARN("File \"" + path + "\" is little-endian, so is not format-compliant (may have been generated using an older MRtrix3 version); " + "imported contents will be converted to system big-endian"); + } else { + INFO("File \"" + path + "\" is big-endian; no format conversion required as executing on big-endian system"); + } +#else + if (change_endianness) { + INFO("Converting imported contents of file \"" + path + "\" to native little-endian"); + } else { + WARN("File \"" + path + "\" already in native little-endian format, so no endianness conversion required; " + "but file is therefore not format-compliant (may have been generated using an older MRtrix3 version)"); + } +#endif + } + + if (change_endianness) { + for (auto& v : vertices) { + for (size_t i = 0; i != 3; ++i) + v[i] = ByteOrder::swap (v[i]); + } + for (auto& v : vertices_float) { + for (size_t i = 0; i != 3; ++i) + v[i] = ByteOrder::swap (v[i]); + } + for (auto& t : triangles) { + for (size_t i = 0; i != 3; ++i) + t[i] = ByteOrder::swap (t[i]); + } + for (auto& q : quads) { + for (size_t i = 0; i != 4; ++i) + q[i] = ByteOrder::swap (q[i]); + } + } + + if (vertices_float.size()) { + assert (!vertices.size()); + for (const auto& v : vertices_float) + vertices.emplace_back (Vertex (v.cast())); + } try { verify_data(); - } catch(Exception& e) { + } catch (Exception& e) { throw Exception (e, "Error verifying surface data from VTK file \"" + path + "\""); } } @@ -627,66 +686,49 @@ namespace MR ProgressBar progress ("writing mesh to file", vertices.size() + triangles.size() + quads.size()); if (binary) { - // FIXME Binary VTK output _still_ not working (crashes ParaView) - // Can however export as binary then -reconvert to ASCII and al is well...? - // Changed to big-endian output, doesn't seem to have fixed... - out.close(); out.open (path, std::ios_base::out | std::ios_base::app | std::ios_base::binary); - const bool is_double = (sizeof(default_type) == 8); - const std::string str_datatype = is_double ? "double" : "float"; - const std::string points_header ("POINTS " + str(vertices.size()) + " " + str_datatype + "\n"); + const std::string points_header ("POINTS " + str(vertices.size()) + " float\n"); out.write (points_header.c_str(), points_header.size()); - for (VertexList::const_iterator i = vertices.begin(); i != vertices.end(); ++i) { - //float temp[3]; - //for (size_t id = 0; id != 3; ++id) - // MR::putBE ((*i)[id], &temp[id]); - if (is_double) { - const double temp[3] { double((*i)[0]), double((*i)[1]), double((*i)[2]) }; - out.write (reinterpret_cast(temp), 3 * sizeof(double)); - } else { - const float temp[3] { float((*i)[0]), float((*i)[1]), float((*i)[2]) }; - out.write (reinterpret_cast(temp), 3 * sizeof(float)); - } + std::array temp_vertex; + for (const auto& v : vertices) { + temp_vertex = { ByteOrder::BE (float(v[0])), ByteOrder::BE (float(v[1])), ByteOrder::BE (float(v[2])) }; + out.write (reinterpret_cast(&temp_vertex), 3 * sizeof(float)); ++progress; } const std::string polygons_header ("POLYGONS " + str(triangles.size() + quads.size()) + " " + str(4*triangles.size() + 5*quads.size()) + "\n"); out.write (polygons_header.c_str(), polygons_header.size()); - const uint32_t num_points_triangle = 3; - for (TriangleList::const_iterator i = triangles.begin(); i != triangles.end(); ++i) { + const uint32_t num_points_triangle = ByteOrder::BE (uint32_t(3)); + std::array temp_triangle; + for (const auto& t : triangles) { out.write (reinterpret_cast(&num_points_triangle), sizeof(uint32_t)); - //uint32_t temp[3]; - //for (size_t id = 0; id != 3; ++id) - // MR::putBE ((*i)[id], &temp[id]); - const uint32_t temp[3] { (*i)[0], (*i)[1], (*i)[2] }; - out.write (reinterpret_cast(temp), 3 * sizeof(uint32_t)); + temp_triangle = { ByteOrder::BE (t[0]), ByteOrder::BE (t[1]), ByteOrder::BE (t[2]) }; + out.write (reinterpret_cast(&temp_triangle), 3 * sizeof(uint32_t)); ++progress; } - const uint32_t num_points_quad = 4; - for (QuadList::const_iterator i = quads.begin(); i != quads.end(); ++i) { + const uint32_t num_points_quad = ByteOrder::BE (uint32_t(4)); + std::array temp_quad; + for (const auto& q : quads) { out.write (reinterpret_cast(&num_points_quad), sizeof(uint32_t)); - //uint32_t temp[4]; - //for (size_t id = 0; id != 4; ++id) - // MR::putBE ((*i)[id], &temp[id]); - const uint32_t temp[4] { (*i)[0], (*i)[1], (*i)[2], (*i)[3] }; - out.write (reinterpret_cast(temp), 4 * sizeof(uint32_t)); + temp_quad = { ByteOrder::BE (q[0]), ByteOrder::BE (q[1]), ByteOrder::BE (q[2]), ByteOrder::BE (q[3]) }; + out.write (reinterpret_cast(&temp_quad), 4 * sizeof(uint32_t)); ++progress; } } else { out << "POINTS " << str(vertices.size()) << " float\n"; - for (VertexList::const_iterator i = vertices.begin(); i != vertices.end(); ++i) { - out << str((*i)[0]) << " " << str((*i)[1]) << " " << str((*i)[2]) << "\n"; + for (const auto& v : vertices) { + out << str(v[0]) << " " << str(v[1]) << " " << str(v[2]) << "\n"; ++progress; } out << "POLYGONS " + str(triangles.size() + quads.size()) + " " + str(4*triangles.size() + 5*quads.size()) + "\n"; - for (TriangleList::const_iterator i = triangles.begin(); i != triangles.end(); ++i) { - out << "3 " << str((*i)[0]) << " " << str((*i)[1]) << " " << str((*i)[2]) << "\n"; + for (const auto& t : triangles) { + out << "3 " << str(t[0]) << " " << str(t[1]) << " " << str(t[2]) << "\n"; ++progress; } - for (QuadList::const_iterator i = quads.begin(); i != quads.end(); ++i) { - out << "4 " << str((*i)[0]) << " " << str((*i)[1]) << " " << str((*i)[2]) << " " << str((*i)[3]) << "\n"; + for (const auto& q : quads) { + out << "4 " << str(q[0]) << " " << str(q[1]) << " " << str(q[2]) << " " << str(q[3]) << "\n"; ++progress; } diff --git a/testing/binaries/data b/testing/binaries/data index 9e39b6044d..747223c963 160000 --- a/testing/binaries/data +++ b/testing/binaries/data @@ -1 +1 @@ -Subproject commit 9e39b6044d3d98403ddfb330fa0cbdc8c42cbbfe +Subproject commit 747223c9635094939d55dd6c639a6e07c1c84427 diff --git a/testing/binaries/tests/mesh2voxel b/testing/binaries/tests/mesh2voxel index fe419fbb18..c893b8c318 100644 --- a/testing/binaries/tests/mesh2voxel +++ b/testing/binaries/tests/mesh2voxel @@ -1 +1 @@ -mesh2voxel meshconvert/in.vtk meshconvert/image.mif.gz - | testing_diff_image - mesh2voxel/out.mif.gz -abs 1.5e-3 +mesh2voxel meshconvert/in_ascii.vtk meshconvert/image.mif.gz - | testing_diff_image - mesh2voxel/out.mif.gz -abs 1.5e-3 diff --git a/testing/binaries/tests/meshconvert b/testing/binaries/tests/meshconvert index 2a762d25bf..38683a4686 100644 --- a/testing/binaries/tests/meshconvert +++ b/testing/binaries/tests/meshconvert @@ -1,10 +1,12 @@ -meshconvert meshconvert/in.vtk tmp.vtk -force && testing_diff_mesh tmp.vtk meshconvert/in.vtk 0.001 -meshconvert meshconvert/in.vtk tmp.vtk -binary -force && testing_diff_mesh tmp.vtk meshconvert/in.vtk 0.001 -meshconvert meshconvert/in.vtk tmp.obj -force && testing_diff_mesh tmp.obj meshconvert/in.vtk 0.001 -meshconvert meshconvert/in.vtk tmp.obj -binary -force && testing_diff_mesh tmp.obj meshconvert/in.vtk 0.001 -meshconvert meshconvert/in.vtk tmp.stl -force && testing_diff_mesh tmp.stl meshconvert/in.vtk 0.001 -meshconvert meshconvert/in.vtk tmp.stl -binary -force && testing_diff_mesh tmp.stl meshconvert/in.vtk 0.001 -meshconvert meshconvert/in.vtk tmp.vtk -transform real2first meshconvert/image.mif.gz -force && testing_diff_mesh tmp.vtk meshconvert/first.vtk 0.001 -meshconvert meshconvert/first.vtk tmp.vtk -transform first2real meshconvert/image.mif.gz -force && testing_diff_mesh tmp.vtk meshconvert/in.vtk 0.001 -meshconvert meshconvert/in.vtk tmp.vtk -transform real2voxel meshconvert/image.mif.gz -force && testing_diff_mesh tmp.vtk meshconvert/voxel.vtk 0.001 -meshconvert meshconvert/voxel.vtk tmp.vtk -transform voxel2real meshconvert/image.mif.gz -force && testing_diff_mesh tmp.vtk meshconvert/in.vtk 0.001 +meshconvert meshconvert/in_ascii.vtk tmp.vtk -force && testing_diff_mesh tmp.vtk meshconvert/in_ascii.vtk 0.001 +meshconvert meshconvert/in_ascii.vtk tmp.vtk -binary -force && testing_diff_mesh tmp.vtk meshconvert/in_ascii.vtk 0.001 +meshconvert meshconvert/in_ascii.vtk tmp.obj -force && testing_diff_mesh tmp.obj meshconvert/in_ascii.vtk 0.001 +meshconvert meshconvert/in_ascii.vtk tmp.obj -binary -force && testing_diff_mesh tmp.obj meshconvert/in_ascii.vtk 0.001 +meshconvert meshconvert/in_ascii.vtk tmp.stl -force && testing_diff_mesh tmp.stl meshconvert/in_ascii.vtk 0.001 +meshconvert meshconvert/in_ascii.vtk tmp.stl -binary -force && testing_diff_mesh tmp.stl meshconvert/in_ascii.vtk 0.001 +meshconvert meshconvert/in_ascii.vtk tmp.vtk -transform real2first meshconvert/image.mif.gz -force && testing_diff_mesh tmp.vtk meshconvert/first.vtk 0.001 +meshconvert meshconvert/first.vtk tmp.vtk -transform first2real meshconvert/image.mif.gz -force && testing_diff_mesh tmp.vtk meshconvert/in_ascii.vtk 0.001 +meshconvert meshconvert/in_ascii.vtk tmp.vtk -transform real2voxel meshconvert/image.mif.gz -force && testing_diff_mesh tmp.vtk meshconvert/voxel.vtk 0.001 +meshconvert meshconvert/voxel.vtk tmp.vtk -transform voxel2real meshconvert/image.mif.gz -force && testing_diff_mesh tmp.vtk meshconvert/in_ascii.vtk 0.001 +meshconvert meshconvert/in_le.vtk tmp.vtk -force && testing_diff_mesh tmp.vtk meshconvert/in_ascii.vtk 0.001 +meshconvert meshconvert/in_be.vtk tmp.vtk -force && testing_diff_mesh tmp.vtk meshconvert/in_ascii.vtk 0.001