CustusX  15.4.0-beta
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxPipeline.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) 2008-2014, SINTEF Department of Medical Technology
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software
19  without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 =========================================================================*/
32 #include "cxPipeline.h"
33 #include "cxTypeConversions.h"
34 
35 #include <QtCore>
36 #include "boost/bind.hpp"
37 #include "libQtSignalAdapters/Qt2Func.h"
38 #include "libQtSignalAdapters/ConnectionFactories.h"
39 
40 
41 #include "cxLogger.h"
42 #include "cxBoolPropertyBase.h"
43 #include "cxDoublePropertyBase.h"
44 #include "cxColorPropertyBase.h"
45 #include "cxStringPropertyBase.h"
47 #include "cxFilterTimedAlgorithm.h"
48 
49 namespace cx
50 {
51 
52 
56 {
58  return retval;
59 }
60 
64  SelectDataStringPropertyBase(patientModelService)
65 {
66  mBase = base;
67  mInput = input;
68  connect(mInput.get(), SIGNAL(changed()), this, SLOT(inputDataChangedSlot()));
69  // connect(mInput.get(), SIGNAL(dataChanged(QString)), this, SLOT(inputDataChangedSlot()));
70  connect(mBase.get(), SIGNAL(dataChanged(QString)), this, SIGNAL(dataChanged(QString)));
71  connect(mBase.get(), SIGNAL(changed()), this, SLOT(changedSlot()));
72  connect(mBase.get(), SIGNAL(changed()), this, SIGNAL(changed()));
73 }
74 
75 
77 {
78  return mBase->setValue(value);
79 }
80 
82 {
83  return mBase->getValue();
84 }
85 
87 {
88  if (mValueName.isEmpty())
89  return mBase->getDisplayName();
90  return mValueName;
91 }
92 
94 {
95  return mBase->getValueRange();
96 }
97 
99 {
100  return mBase->convertInternal2Display(internal);
101 }
102 
104 {
105 // return mBase->getHelp();
106  return QString("<html>"
107  "<h4>%1</h4> <p>%2</p>"
108  "<h4>%3</h4> <p>%4</p>"
109  "</html>")
110  .arg("Input").arg(mInput->getHelp())
111  .arg("Output").arg(mBase->getHelp());
112 }
113 
115 {
116  return mBase->getData();
117 }
118 
120 {
121  if (name==mValueName)
122  return;
123  // mBase->setValueName(name);
124  mValueName = name;
125  emit changed();
126 }
127 
129 {
130  mBase->setHelp(text);
131 }
132 
134 {
135  // this sync helps the pipeline behaving when the output is changed.
136  this->blockSignals(true);
137  mInput->setValue(mBase->getValue());
138  this->blockSignals(false);
139 }
140 
142 {
143  // the entire point of the class: update mBase when mInput is changed:
144  mBase->setValue(mInput->getValue());
145 }
146 
147 
148 
152 
153 
154 Pipeline::Pipeline(PatientModelServicePtr patientModelService, QObject *parent) :
155  QObject(parent),
156  mPatientModelService(patientModelService)
157 {
158  mCompositeTimedAlgorithm.reset(new CompositeSerialTimedAlgorithm("Pipeline"));
159 }
160 
162 {
163  mFilters = filters;
164 
165  for (unsigned i=0; i<mFilters->size(); ++i)
166  {
167  FilterPtr filter = mFilters->get(i);
168  filter->getInputTypes();
169  filter->getOutputTypes();
170  filter->getOptions();
171  }
172 
173  this->getNodes();
174 
175  for (unsigned i=0; i<mFilters->size(); ++i)
176  {
177  FilterPtr current = mFilters->get(i);
178  mTimedAlgorithm[current->getUid()].reset(new FilterTimedAlgorithm(current));
179  }
180 }
182 {
183  return mFilters;
184 }
185 
191 void Pipeline::setOption(QString valueName, QVariant value)
192 {
193  for (unsigned i=0; i<mFilters->size(); ++i)
194  {
195  FilterPtr filter = mFilters->get(i);
196  std::vector<PropertyPtr> options = filter->getOptions();
197 
198  for (unsigned j=0; j<options.size(); ++j)
199  {
200  if (options[j]->getDisplayName()==valueName)
201  this->setOption(options[j], value);
202  }
203  }
204 }
205 
206 void Pipeline::setOption(PropertyPtr adapter, QVariant value)
207 {
208  if (value.canConvert<bool>())
209  {
210  BoolPropertyBasePtr specific = boost::dynamic_pointer_cast<BoolPropertyBase>(adapter);
211  if (specific)
212  specific->setValue(qvariant_cast<bool>(value));
213  }
214  else if (value.canConvert<double>())
215  {
216  DoublePropertyBasePtr specific = boost::dynamic_pointer_cast<DoublePropertyBase>(adapter);
217  if (specific)
218  specific->setValue(qvariant_cast<double>(value));
219  }
220  else if (value.canConvert<QColor>())
221  {
222  ColorPropertyBasePtr specific = boost::dynamic_pointer_cast<ColorPropertyBase>(adapter);
223  if (specific)
224  specific->setValue(qvariant_cast<QColor>(value));
225  }
226  else if (value.canConvert<QString>())
227  {
228  StringPropertyBasePtr specific = boost::dynamic_pointer_cast<StringPropertyBase>(adapter);
229  if (specific)
230  specific->setValue(qvariant_cast<QString>(value));
231  }
232  else
233  {
234  reportWarning(QString("Attempt to set option of type %2 is not supported").arg(value.typeName()));
235  }
236 }
237 
238 
239 std::vector<SelectDataStringPropertyBasePtr> Pipeline::getNodes()
240 {
241  // TODO: create getMainXXType() in filters instead of using zero.
242 
243  if (mNodes.empty())
244  mNodes = this->createNodes();
245  return mNodes;
246 }
247 
248 std::vector<SelectDataStringPropertyBasePtr> Pipeline::createNodes()
249 {
250  // TODO: create fused nodes: input+output
251  // TODO: create getMainXXType() in filters instead of using zero.
252 
253  std::vector<SelectDataStringPropertyBasePtr> retval;
254 
255  if (mFilters->empty())
256  return retval;
257 
258  // first node is the input of the first algo
259  retval.push_back(mFilters->get(0)->getInputTypes()[0]);
260 
261  // intermediate nodes are fusions between output and input
262  for (unsigned i=1; i<mFilters->size(); ++i)
263  {
264  SelectDataStringPropertyBasePtr output = mFilters->get(i-1)->getOutputTypes()[0];
265  SelectDataStringPropertyBasePtr base = mFilters->get(i)->getInputTypes()[0];
267  node = StringPropertyFusedInputOutputSelectData::create(mPatientModelService, base, output);
268  node->setValueName(QString("Node %1").arg(i));
269  retval.push_back(node);
270  }
271 
272  // last node is the output of the last algo
273  retval.push_back(mFilters->get(mFilters->size()-1)->getOutputTypes()[0]);
274 
275  for (unsigned i=0; i<retval.size(); ++i)
276  QtSignalAdapters::connect1<void(QString)>(retval[i].get(), SIGNAL(dataChanged(QString)),
277  boost::bind(&Pipeline::nodeValueChanged, this, _1, i));
278 
279  return retval;
280 }
281 
282 
283 void Pipeline::nodeValueChanged(QString uid, int index)
284 {
285  // std::cout << "Pipeline::nodeValueChanged(QString uid, int index) " << uid << " " << index << std::endl;
286 
287  // clear all nodes beyond the input:
288  for (unsigned i=index+1; i<mNodes.size(); ++i)
289  mNodes[i]->setValue("");
290 }
291 
293 {
294  return mTimedAlgorithm[uid];
295 }
296 
298 {
299  return mCompositeTimedAlgorithm;
300 }
301 
302 void Pipeline::execute(QString uid)
303 {
304  // generate |startIndex, endIndex>, pointing to the filters to be executed
305 
306  int endIndex = -1;
307  int startIndex = endIndex;
308 
309  if (uid.isEmpty()) // execute entire pipeline, if necessary
310  {
311  endIndex = mFilters->size();
312  startIndex = endIndex;
313  }
314  else // execute at least one given filter, more if necessary
315  {
316  for (unsigned i=0; i<mFilters->size(); ++i)
317  if (mFilters->get(i)->getUid()==uid)
318  endIndex = i+1; // set end index to after filter to execute;
319  startIndex = endIndex-1;
320  }
321 
322  if (endIndex<0) // input filter not found: ignore
323  return;
324 
325 // // filter i require node i as input
326 
327  // int startIndex = endIndex;
328 
329  // index now counts filters <0...N-1>
330  // nodes are <0...N>
331 
332  for ( ; startIndex>=-1; --startIndex)
333  {
334  if (startIndex<0)
335  break;
336  if (mNodes[startIndex]->getData()) // index output node for filter[startIndex]
337  break; // found node with data: stop here
338  }
339 
340  std::cout << "Pipeline::execute filter range s=|" << startIndex << "," << endIndex << ">" << std::endl;
341 
342  if (startIndex<0)
343  {
344  reportWarning(QString("Cannot execute filter %1: No input data set").arg(uid));
345  return;
346  }
347 
348  mCompositeTimedAlgorithm->clear();
349  for (unsigned i=startIndex; i<endIndex; ++i)
350  mCompositeTimedAlgorithm->append(mTimedAlgorithm[mFilters->get(i)->getUid()]);
351 
352  // run all filters
353  mCompositeTimedAlgorithm->execute();
354 }
355 
356 //void Pipeline::execute(QString uid)
357 //{
358 // // no input uid: execute entire pipeline
359 // if (uid.isEmpty())
360 // uid = mFilters->get(mFilters->size()-1)->getUid();
361 
362 // int endIndex = -1;
363 
364 // for (unsigned i=0; i<mFilters->size(); ++i)
365 // if (mFilters->get(i)->getUid()==uid)
366 // endIndex = i;
367 // if (endIndex<0)
368 // return;
369 
370 // // filter i require node i as input
371 // int startIndex = endIndex;
372 
373 // // index now counts filters <0...N-1>
374 // // nodes are <0...N>
375 
376 // for ( ; startIndex>=-1; --startIndex)
377 // {
378 // if (startIndex<0)
379 // break;
380 // if (mNodes[startIndex+1]->getData()) // index output node for filter[startIndex]
381 // break; // found node with data: stop here
382 // }
383 
384 // std::cout << "Pipeline::execute3 s=" << startIndex << ", e=" << endIndex << std::endl;
385 
386 // if (startIndex<0)
387 // {
388 // reportWarning(QString("Cannot execute filter %1: No input data set").arg(uid));
389 // return;
390 // }
391 
392 // mCompositeTimedAlgorithm->clear();
393 // for (unsigned i=startIndex; i<=endIndex; ++i)
394 // mCompositeTimedAlgorithm->append(mTimedAlgorithm[mFilters->get(i)->getUid()]);
395 
396 // // run all filters
397 // mCompositeTimedAlgorithm->execute();
398 //}
399 
400 
401 } // namespace cx
virtual bool setValue(bool value)=0
set the data value.
void nodeValueChanged(QString uid, int index)
Definition: cxPipeline.cpp:283
Pipeline(PatientModelServicePtr patientModelService, QObject *parent=0)
Definition: cxPipeline.cpp:154
FilterGroupPtr getFilters() const
Definition: cxPipeline.cpp:181
static StringPropertyFusedInputOutputSelectDataPtr create(PatientModelServicePtr patientModelService, SelectDataStringPropertyBasePtr base, SelectDataStringPropertyBasePtr input)
Definition: cxPipeline.cpp:53
SelectDataStringPropertyBasePtr mInput
Definition: cxPipeline.h:85
void execute(QString uid="")
Definition: cxPipeline.cpp:302
virtual QStringList getValueRange() const
Definition: cxPipeline.cpp:93
virtual QString getValue() const
get the data value.
Definition: cxPipeline.cpp:81
virtual QString convertInternal2Display(QString internal)
range of value. Use if data is constrained to a set.
Definition: cxPipeline.cpp:98
virtual QString getHelp() const
return a descriptive help string for the data, used for example as a tool tip.
Definition: cxPipeline.cpp:103
virtual QString getDisplayName() const
name of data entity. Used for display to user.
Definition: cxPipeline.cpp:86
virtual void setValueName(const QString name)
Definition: cxPipeline.cpp:119
void initialize(FilterGroupPtr filter)
Definition: cxPipeline.cpp:161
StringPropertyFusedInputOutputSelectData(PatientModelServicePtr patientModelService, SelectDataStringPropertyBasePtr base, SelectDataStringPropertyBasePtr input)
Definition: cxPipeline.cpp:61
virtual bool setValue(const QString &value)
set the data value.
Definition: cxPipeline.cpp:76
boost::shared_ptr< class Data > DataPtr
boost::shared_ptr< class Filter > FilterPtr
boost::shared_ptr< class SelectDataStringPropertyBase > SelectDataStringPropertyBasePtr
boost::shared_ptr< class TimedBaseAlgorithm > TimedAlgorithmPtr
void setOption(QString valueName, QVariant value)
Definition: cxPipeline.cpp:191
boost::shared_ptr< class Property > PropertyPtr
void reportWarning(QString msg)
Definition: cxLogger.cpp:91
boost::shared_ptr< class StringPropertyFusedInputOutputSelectData > StringPropertyFusedInputOutputSelectDataPtr
Definition: cxPipeline.h:47
boost::shared_ptr< class BoolPropertyBase > BoolPropertyBasePtr
boost::shared_ptr< class PatientModelService > PatientModelServicePtr
boost::shared_ptr< FilterGroup > FilterGroupPtr
Definition: cxFilterGroup.h:86
boost::shared_ptr< class DoublePropertyBase > DoublePropertyBasePtr
void changed()
emit when the underlying data value is changed: The user interface will be updated.
TimedAlgorithmPtr getTimedAlgorithm(QString uid)
Definition: cxPipeline.cpp:292
boost::shared_ptr< class ColorPropertyBase > ColorPropertyBasePtr
SelectDataStringPropertyBasePtr mBase
Definition: cxPipeline.h:86
std::vector< SelectDataStringPropertyBasePtr > getNodes()
Definition: cxPipeline.cpp:239
TimedAlgorithmPtr getPipelineTimedAlgorithm()
Definition: cxPipeline.cpp:297
boost::shared_ptr< class StringPropertyBase > StringPropertyBasePtr