18 #include "milxQtDiffusionTensorModel.h" 24 #include <vtkSphereSource.h> 26 #include <boost/math/special_functions/spherical_harmonic.hpp> 28 milxQtDiffusionTensorModel::milxQtDiffusionTensorModel(QWidget *theParent) :
milxQtModel(theParent)
37 milxQtDiffusionTensorModel::~milxQtDiffusionTensorModel()
44 vtkSmartPointer<vtkPolyData> currentMesh = model.Result();
46 typedef double projectionType;
49 vtkSmartPointer<vtkUnsignedCharArray> scalars = vtkSmartPointer<vtkUnsignedCharArray>::New();
50 scalars->SetNumberOfComponents(3);
51 scalars->SetNumberOfTuples(currentMesh->GetNumberOfPoints());
52 scalars->SetName(
"Fibre Colours");
53 scalars->FillComponent(0, 0);
54 scalars->FillComponent(1, 0);
55 scalars->FillComponent(2, 0);
56 vtkSmartPointer<vtkFloatArray> projections = vtkSmartPointer<vtkFloatArray>::New();
57 projections->SetNumberOfComponents(3);
58 projections->SetNumberOfTuples(currentMesh->GetNumberOfPoints());
59 projections->SetName(
"Fibre Projections");
60 projections->FillComponent(0, 0.0);
61 projections->FillComponent(1, 0.0);
62 projections->FillComponent(2, 0.0);
65 if(currentMesh->GetNumberOfLines() == 0)
67 printInfo(
"No lines in model. Computing colours for mesh.");
70 for(
size_t j = 0; j < 3; j ++)
72 projectionType axis[3] = {0.0, 0.0, 0.0};
74 cout <<
"Computing toward axis " << j << endl;
77 for(vtkIdType k = 0; k < currentMesh->GetNumberOfPoints(); k ++)
79 coordinate currentProjection(projections->GetTuple3(k)), position(currentMesh->GetPoint(k));
81 projectionType projection = vtkMath::Dot(axis, position.data_block());
82 currentProjection[j] = projection;
84 projections->SetTuple3(k, currentProjection[0], currentProjection[1], currentProjection[2]);
89 for(vtkIdType k = 0; k < currentMesh->GetNumberOfPoints(); k ++)
91 coordinate currentProjection(projections->GetTuple3(k));
92 coordinate currentProjSquared = element_product(currentProjection, currentProjection);
93 projectionType maxProjection = currentProjSquared.max_value();
94 currentProjSquared /= maxProjection;
96 unsigned char colourOfPoint[3] = {0, 0, 0};
97 colourOfPoint[0] =
static_cast<unsigned char>( currentProjSquared[0]*255.0 );
98 colourOfPoint[1] =
static_cast<unsigned char>( currentProjSquared[1]*255.0 );
99 colourOfPoint[2] =
static_cast<unsigned char>( currentProjSquared[2]*255.0 );
101 scalars->SetTupleValue(k, colourOfPoint);
104 currentMesh->GetPointData()->SetVectors(projections);
105 currentMesh->GetPointData()->SetScalars(scalars);
109 printInfo(
"Re-colouring lines by axes directions");
111 currentMesh->GetLines()->InitTraversal();
112 vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
113 vtkSmartPointer<vtkIdList> idList = vtkSmartPointer<vtkIdList>::New();
114 std::vector<vtkIdType> trackLengths;
115 for(vtkIdType j = 0; j < currentMesh->GetNumberOfLines(); j ++)
117 currentMesh->GetLines()->GetNextCell(idList);
118 trackLengths.push_back(idList->GetNumberOfIds());
119 for(vtkIdType pointId = 0; pointId < idList->GetNumberOfIds(); pointId ++)
124 currentMesh->GetPoint(idList->GetId(pointId), position);
125 points->InsertNextPoint(position);
131 vtkSmartPointer<vtkCellArray> lines = vtkSmartPointer<vtkCellArray>::New();
132 for(
size_t j = 0; j < trackLengths.size(); j ++)
134 for(vtkIdType k = step; k < trackLengths[j]-1; k ++)
136 vtkSmartPointer<vtkLine> line = vtkSmartPointer<vtkLine>::New();
137 line->GetPointIds()->SetId(0, k);
138 line->GetPointIds()->SetId(1, k+1);
139 lines->InsertNextCell(line);
141 qDebug() << trackLengths[j] << endl;
142 step += trackLengths[j];
145 vtkSmartPointer<vtkPolyData> linesPolyData = vtkSmartPointer<vtkPolyData>::New();
147 linesPolyData->SetPoints(points);
149 linesPolyData->SetLines(lines);
150 linesPolyData->Modified();
151 model.SetInput(linesPolyData);
161 if(ordersString.isEmpty())
163 ordersString = QInputDialog::getText(
this, tr(
"Enter order magnitudes of harmonics separated by spaces"),
164 tr(
"Orders: "), QLineEdit::Normal,
165 "1 0 0 0 1 1 1 1 1", &ok);
167 if (!ok || ordersString.isEmpty())
170 QStringList orders = ordersString.split(
" ");
171 std::vector<double> sHarmonicCoefficients;
172 for(
int i = 0; i < orders.size(); i++)
173 sHarmonicCoefficients.push_back(orders[i].toDouble());
175 int n_coefs = sHarmonicCoefficients.size();
176 int l_max = milxQtDiffusionTensorModel::LforN( n_coefs );
178 vtkSmartPointer<vtkSphereSource> sphereSource = vtkSmartPointer<vtkSphereSource>::New();
179 sphereSource->SetThetaResolution( 64 );
180 sphereSource->SetPhiResolution( 64 );
181 sphereSource->SetRadius( 1.0 );
182 sphereSource->Update();
183 vtkSmartPointer<vtkPolyData> glyph = sphereSource->GetOutput();
186 double m_x = 0, m_y = 0, m_z = 0;
187 for(
int i = 0; i < glyph->GetNumberOfPoints(); i++)
189 double point_sphere[3];
190 glyph->GetPoint(i, point_sphere);
191 double x_s = point_sphere[0];
192 double y_s = point_sphere[1];
193 double z_s = point_sphere[2];
195 double x_g, y_g, z_g;
198 double amplitude = computeAmplitude( sHarmonicCoefficients, x_s, y_s, z_s, l_max );
204 x_g = x_s * amplitude + m_x;
205 y_g = y_s * amplitude + m_y;
206 z_g = z_s * amplitude + m_z;
208 glyph->GetPoints()->SetPoint(i, x_g, y_g, z_g);
211 model.SetInput(glyph);
212 model.GenerateNormals(
true);
218 double milxQtDiffusionTensorModel::computeAmplitude(std::vector<double> SH,
double x,
double y,
double z,
int lmax)
220 double az = atan2(y, x);
223 for (
int l = 0; l <= lmax; l+=2)
226 val += SH[milxQtDiffusionTensorModel::index(l,0)] * boost::math::spherical_harmonic_r<double>(l, 0, el,az);
229 for (
int m = 1; m <= lmax; m++)
233 for (
int l = 2*((m+1)/2); l <= lmax; l+=2)
238 val += SH[milxQtDiffusionTensorModel::index(l,m)]*boost::math::spherical_harmonic_r(l,m,el,az);
239 val += SH[milxQtDiffusionTensorModel::index(l,-m)]*boost::math::spherical_harmonic_i(l,m,el,az);
246 void milxQtDiffusionTensorModel::createActions()
248 colourDirectionAct =
new QAction(
this);
249 colourDirectionAct->setText(QApplication::translate(
"Model",
"Colour By Direction", 0, QApplication::UnicodeUTF8));
250 colourDirectionAct->setShortcut(tr(
"Alt+c"));
251 harmonicsAct =
new QAction(
this);
252 harmonicsAct->setText(QApplication::translate(
"Model",
"Show Spherical Harmonic ...", 0, QApplication::UnicodeUTF8));
253 harmonicsAct->setShortcut(tr(
"Alt+s"));
256 void milxQtDiffusionTensorModel::createConnections()
259 connect(colourDirectionAct, SIGNAL(triggered()),
this, SLOT(colourByDirection()));
260 connect(harmonicsAct, SIGNAL(triggered()),
this, SLOT(harmonics()));
265 void milxQtDiffusionTensorModel::contextMenuEvent(QContextMenuEvent *currentEvent)
269 contextMenu->addSeparator()->setText(tr(
"DiffusionTensor"));
272 contextMenu->addSeparator()->setText(tr(
"Extensions"));
QAction * scaleAct
Action for the scale bar of the display.
QList< QAction * > extActionsToAdd
Extension actions to add.
void harmonics(QString ordersString="")
QMenu * contextMenu
Context Menu.
QAction * axesAct
Action for axes of the display.
QString prefix
Prefix of the data.
This class represents the MILX Qt Model/Mesh Display object using VTK.
QMenu * basicContextMenu()
Return the basic context menu with the milxQtModel class ordering. This is for the benefit of derived...
QAction * refreshAct
Action for refreshing the display.
void reset()
Reset the rendering, camera and windowing.
void done(int value)
Send signal that computation is done. Value carries the progress,.
void printInfo(QString msg)
Info message wrapper for console.
void working(int value)
Send signal that computation is in progress. Value carries the progress,.