<div dir="ltr"><div>Hi David,<br><br></div>Thanks a lot for the thorough advice/explanation! See my comments inline.<br><div><div class="gmail_extra"><br><div class="gmail_quote">2016-06-28 21:01 GMT+02:00 David Gobbi <span dir="ltr"><<a href="mailto:david.gobbi@gmail.com" target="_blank">david.gobbi@gmail.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span class="">On Tue, Jun 28, 2016 at 12:04 PM, Elvis Stansvik <span dir="ltr"><<a href="mailto:elvis.stansvik@orexplore.com" target="_blank">elvis.stansvik@orexplore.com</a>></span> wrote:<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div><br></div><div>So my question is: What is the proper way of "unhooking" (or "disabling" if you will) a pipeline? I want the render window to simply show empty space when in this state, but still have the entire pipeline intact and ready for when I next want to set the filename of the reader to a valid volume.</div></div></blockquote><div><br></div></span><div>I've found it convenient to build the pipeline in segments, with shallow copies as necessary to connect the segments.</div><div><br></div><div>For example, the reader is handled like this (drastically simplified code):</div><div><br></div><div>void ReadImage(vtkImageData *data, const char *filename)</div><div>{</div><div> vtkSmartPointer<vtkImageReader2> reader = vtkSmartPointer<vtkImageReader2>::New();</div><div> reader->SetFileName(filename); </div><div> reader->Update();</div><div><br></div><div> vtkImageData *image = reader->GetOutput();</div><div><br></div><div> // shallow copy the data into the supplied data object</div><div> data->CopyStructure(image);</div><div> data->GetPointData()->PassData(image->GetPointData());</div><div>}</div><div><br></div><div>My app has a data management structure (i.e. an object) that contains a list of all the images that the app needs. So to read a new file, I create a new vtkImageData object, call the above function to populate it via the reader, and then I connect it to the rest of my pipeline. The reader object is temporary. By doing my code like this, it's easy to support a broad range of readers.</div></div></div></div></blockquote><div><br></div><div>That's interesting. So if I understand the above correctly, you create a little ad-hoc pipeline for the purpose of reading the file, and then keep only what you need.<br><br>In my case I'm working from Python, though for various reasons I'm at least entertaining the idea of re-writing what I have in C++. But say I stick to Python, would the shallow copying maneuver above be relevant in Python-land?<br> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><br></div><div>Most processing pipelines are done the same way: they exist just long enough to generate an output. Afterwards, the filter objects are deleted and only the output is kept (via a shallow copy done with the CopyStructure()/PassData() calls above).</div></div></div></div></blockquote><div><br></div><div>I see. In my case I'm not going to have any pure-processing pipelines. Most of what I'll use VTK for is interactive visualization, where I may want to tweak certain aspects of the visualization while it is shown (transfer functions, volume of interest extraction bounds, transforms, ...). So I think I want to keep the entire pipeline alive in most cases (but see my question further down), even if some nodes in the pipeline can be "hidden" in the sense that I don't need to keep around references to them. The nodes I do have to keep references to are of course the ones where I'll need to tweak things.<br><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><br></div><div>Display pipelines (e.g. pipelines that terminate with a mapper) have a longer life: when I need to display a new data set, I generate the display pipeline as well as its actors, then I connect an input and add the actors to the renderer. When I unload a data set, I also remove the actors. I have a class for each display pipeline that I need, and objects of these class are instantiated and destructed when data is loaded or unloaded. Having as much of your program logic as possible tied to object construction/destruction helps to simplify things.</div></div></div></div></blockquote><div><br></div><div>Ah, perhaps it would make sense for me to also break out the pipeline construction/destruction logic out of my widget into a separate class, even if I don't have destructors in the C++ sense.<br></div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><br></div><div>Interactive processing pipelines (as opposed to the run-once pipelines) are temporarily connected to a display pipeline via the usual AddInputConnection() mechanism, but when the interaction is complete the following is done: 1) the connection is broken with e.g. RemoveAllInputConnections(), 2) the output is shallow-copied into a new data object with the CopyStructure()/PassData() calls and the processing pipeline is deleted, and 3) the copy is connected directly to the display pipeline (and generally stored in my data management structure, as well).</div></div></div></div></blockquote><div><br></div><div>Hm, now I think I understand what you mean. So you have a general "processing" segment of the pipeline, and a visualization pipeline that follows, and you keep the processing part of it alive only for as long as you need it.<br><br></div><div>I then just have one question I think: What if you later need to "hook up" the processing segment again? Do you discard the shallow copy you made, create a new processing pipeline segment and hook it up to the visualization segment?<br><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><br></div><div>The general idea is that pipeline segments only exist for as long as they are being used, i.e. they are either limited to the scope of a single function, or limited to the lifetime of a specific object. This helps to reduce the overall resource usage of the application.</div></div></div></div></blockquote><div><br></div><div>I like this design, and it makes sense. I'll have to think about it some more.<br><br></div><div>A little about my use case: It's a tool for looking at tomographic images of drilled rock cores, along with some spectral analysis results (plots). The user will be able to see a scale showing drilled depth (~1000 m), with some segments indicating where there are samples available. Clicking such a segment (~1 m) will bring up the volume corresponding to that sample in a VTK view. If the user wishes to go even closer, he/she should be able to select a smaller (~10 cm) segment in the ~1 m view, which will bring that segment up in a third (larger) view which has free zooming/rotation. And another thing is that the user must be able to adjust the color/opacity transfer functions used in the volume rendering. Not everything is ironed out yet, but that's the gist of it, as far as VTK is involved.<br><br></div><div>Again, thanks a lot for your input, you've been very helpful.<br><br></div><div>Elvis<br></div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span class="HOEnZb"><font color="#888888"><div><br></div><div> - David</div><div><br></div></font></span></div></div></div>
</blockquote></div><br></div></div></div>