datacontainerinspectorcanvas.cpp 22.3 KB
Newer Older
1 2
// ================================================================================================
// 
schultezub's avatar
schultezub committed
3
// This file is part of the CAMPVis Software Framework.
4
// 
5
// If not explicitly stated otherwise: Copyright (C) 2012-2015, all rights reserved,
schultezub's avatar
schultezub committed
6
//      Christian Schulte zu Berge <christian.szb@in.tum.de>
7
//      Chair for Computer Aided Medical Procedures
8 9
//      Technische Universitaet Muenchen
//      Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
10
// 
schultezub's avatar
schultezub committed
11
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
12
// 
13 14 15 16
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 
// except in compliance with the License. You may obtain a copy of the License at
// 
// http://www.apache.org/licenses/LICENSE-2.0
17
// 
18 19 20 21
// Unless required by applicable law or agreed to in writing, software distributed under the 
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
// either express or implied. See the License for the specific language governing permissions 
// and limitations under the License.
22 23 24 25 26
// 
// ================================================================================================

#include "datacontainerinspectorcanvas.h"

27 28 29
#include "cgt/assert.h"
#include "cgt/shadermanager.h"
#include "cgt/textureunit.h"
30

31 32
#include "core/datastructures/datacontainer.h"
#include "core/datastructures/datahandle.h"
33
#include "core/datastructures/renderdata.h"
34
#include "core/datastructures/imagerepresentationgl.h"
35
#include "core/datastructures/imagerepresentationlocal.h"
36
#include "core/datastructures/facegeometry.h"
37
#include "core/datastructures/geometrydatafactory.h"
38 39
#include "core/classification/tfgeometry1d.h"
#include "core/classification/geometry1dtransferfunction.h"
40
#include "core/tools/simplejobprocessor.h"
41

42 43
#include "datacontainerinspectorwidget.h"

44
#include "ext/cgt/navigation/trackball.h"
45

46
#include <QWindow>
47

schultezub's avatar
schultezub committed
48
namespace campvis {
49 50

    DataContainerInspectorCanvas::DataContainerInspectorCanvas(QWidget* parent /*= 0*/) 
51
        : cgt::QtThreadedCanvas("DataContainer Inspector", cgt::ivec2(640, 480), cgt::GLCanvas::RGBA_BUFFER, parent, true)
52
        , p_currentSlice("CurrentSlice", "Slice", -1, -1, -1)
53
        , p_transferFunction("TransferFunction", "Transfer Function", new Geometry1DTransferFunction(256, cgt::vec2(0.f, 1.f)))
54 55 56 57
        , p_renderRChannel("RenderRChannel", "Render Red Channel", true)
        , p_renderGChannel("RenderGChannel", "Render Green Channel", true)
        , p_renderBChannel("RenderBChannel", "Render Blue Channel", true)
        , p_renderAChannel("RenderAChannel", "Render Alpha Channel", true)
58 59
        , p_geometryRendererProperties("GeometryRendererProperties", "GeometryRenderer Properties")
        , _texturesDirty(true)
60
        , _geometriesDirty(true)
61 62 63
        , _dataContainer(nullptr)
        , _paintShader(nullptr)
        , _quad(nullptr)
64 65
        , _numTiles(0, 0)
        , _quadSize(0, 0)
66
        , _localDataContainer("Local DataContainer for DataContainerInspectorCanvas")
67
        , p_viewportSize("ViewportSize", "Viewport Size", cgt::ivec2(200), cgt::ivec2(0, 0), cgt::ivec2(10000))
68
        , _tcp(&p_viewportSize)
69
        , _geometryRenderer(&p_viewportSize)
70
    {
71
        static_cast<Geometry1DTransferFunction*>(p_transferFunction.getTF())->addGeometry(TFGeometry1D::createQuad(cgt::vec2(0.f, 1.f), cgt::col4(0, 0, 0, 255), cgt::col4(255, 255, 255, 255)));
72

73
        GLCtxtMgr.registerContextAndInitGlew(this, "DataContainerInspector");
74
        
75 76 77 78 79 80
        addProperty(p_currentSlice);
        addProperty(p_transferFunction);
        addProperty(p_renderRChannel);
        addProperty(p_renderGChannel);
        addProperty(p_renderBChannel);
        addProperty(p_renderAChannel);
81 82 83 84 85 86

        p_geometryRendererProperties.addPropertyCollection(_geometryRenderer);
        _geometryRenderer.p_geometryID.setVisible(false);
        _geometryRenderer.p_textureID.setVisible(false);
        _geometryRenderer.p_renderTargetID.setVisible(false);
        _geometryRenderer.p_lightId.setVisible(false);
87
        _geometryRenderer.p_camera.setVisible(false);
88 89 90 91 92 93 94 95 96 97
        _geometryRenderer.p_coloringMode.setVisible(false);
        _geometryRenderer.p_pointSize.setVisible(false);
        _geometryRenderer.p_lineWidth.setVisible(false);
        _geometryRenderer.p_showWireframe.setVisible(false);
        _geometryRenderer.p_wireframeColor.setVisible(false);
        _geometryRenderer.p_renderMode.selectByOption(GL_POLYGON);
        _geometryRenderer.p_enableShading.s_changed.connect(this, &DataContainerInspectorCanvas::onGeometryRendererPropertyChanged);
        _geometryRenderer.p_renderMode.s_changed.connect(this, &DataContainerInspectorCanvas::onGeometryRendererPropertyChanged);
        _geometryRenderer.p_solidColor.s_changed.connect(this, &DataContainerInspectorCanvas::onGeometryRendererPropertyChanged);
        addProperty(p_geometryRendererProperties);
98 99 100 101 102 103 104 105

        p_geometryRendererProperties.setVisible(false);
        p_currentSlice.setVisible(false);
        p_transferFunction.setVisible(false);
        p_renderRChannel.setVisible(false);
        p_renderGChannel.setVisible(false);
        p_renderBChannel.setVisible(false);
        p_renderAChannel.setVisible(false);
106

107
		connect(this, &DataContainerInspectorCanvas::s_invalidated, this, &DataContainerInspectorCanvas::onInvalidated);
108

109
        init();
110 111 112 113 114
    }

    DataContainerInspectorCanvas::~DataContainerInspectorCanvas() {
    }

115
    void DataContainerInspectorCanvas::init() {
schultezub's avatar
schultezub committed
116 117
        initAllProperties();

118
        _paintShader = ShdrMgr.load("core/glsl/passthrough.vert", "application/glsl/datacontainerinspector.frag", "");
119 120
        createQuad();

121
        // set this as painter to get notified when window size changes
122
        setPainter(this);
123
        getEventHandler()->addEventListenerToFront(this);
124

125
        _geometryRenderer.init();
Jakob Weiss's avatar
Jakob Weiss committed
126
        _tcp.init();
127 128 129
    }

    void DataContainerInspectorCanvas::deinit() {
schultezub's avatar
schultezub committed
130 131
        deinitAllProperties();

132 133 134 135
        if (_dataContainer != 0) {
            _dataContainer->s_dataAdded.disconnect(this);
        }

136
        _geometryRenderer.deinit();
Jakob Weiss's avatar
Jakob Weiss committed
137
        _tcp.deinit();
mostajab's avatar
mostajab committed
138

139 140
        _handles.clear();
        _localDataContainer.clear();
mostajab's avatar
mostajab committed
141
        _textures.clear();
142
        ShdrMgr.dispose(_paintShader);
143
        _quad = nullptr;
144 145

        GLCtxtMgr.removeContext(this);
146 147 148 149 150 151 152 153
    }

    QSize DataContainerInspectorCanvas::sizeHint() const {
        return QSize(640, 480);
    }

    void DataContainerInspectorCanvas::paint() {
        tbb::mutex::scoped_lock lock(_localMutex);
154
        if (_texturesDirty) {
155
            updateTextures();
156 157 158 159 160 161 162 163
        }
        if (_geometriesDirty) {
            // update geometry renderings if necessary
            for (auto it = _geometryNames.begin(); it != _geometryNames.end(); ++it) {
                renderGeometryIntoTexture(it->first, it->second);
            }
            _geometriesDirty = false;
        }
164 165

        glPushAttrib(GL_ALL_ATTRIB_BITS);
166
        glViewport(0, 0, size_.x, size_.y);
167 168 169 170
        glClearColor(0.7f, 0.7f, 0.7f, 1.f);
        glClear(GL_COLOR_BUFFER_BIT);
        LGL_ERROR;

171 172 173 174 175
        if (_textures.empty()) {
            glPopAttrib();
            return;
        }

176
        // update layout dimensions
177 178
        _numTiles.x = ceil(sqrt(static_cast<float>(_textures.size())));
        _numTiles.y = ceil(static_cast<float>(_textures.size()) / _numTiles.x);
179
        _quadSize = size_ / _numTiles;
180 181 182

        _paintShader->activate();

183
        cgt::mat4 projection = cgt::mat4::createOrtho(0, size_.x, 0, size_.y, -1, 1);
184 185
        _paintShader->setUniform("_projectionMatrix", projection);

186
        cgt::TextureUnit tfUnit, unit2d, unit3d;
187
        p_transferFunction.getTF()->bind(_paintShader, tfUnit);
188 189
        _paintShader->setUniform("_texture2d", unit2d.getUnitNumber());
        _paintShader->setUniform("_texture3d", unit3d.getUnitNumber());
190

191 192 193 194 195
        _paintShader->setUniform("_renderRChannel", p_renderRChannel.getValue());
        _paintShader->setUniform("_renderGChannel", p_renderGChannel.getValue());
        _paintShader->setUniform("_renderBChannel", p_renderBChannel.getValue());
        _paintShader->setUniform("_renderAChannel", p_renderAChannel.getValue());

196 197 198 199 200 201
        for (int y = 0; y < _numTiles.y; ++y) {
            for (int x = 0; x < _numTiles.x; ++x) {
                int index = (_numTiles.x * y) + x;
                if (index >= static_cast<int>(_textures.size()))
                    break;

202
                // gather image
203 204
                cgtAssert(_textures[index].getData<ImageData>(), "Found sth. else than ImageData in render texture vector. This should not happen!");
                auto id = _textures[index].getData<ImageData>();
205 206 207

                // compute transformation matrices
                float renderTargetRatio = static_cast<float>(_quadSize.x) / static_cast<float>(_quadSize.y);
208 209
                float sliceRatio = (static_cast<float>(id->getSize().x) * std::abs(id->getMappingInformation().getVoxelSize().x))
                                 / (static_cast<float>(id->getSize().y) * std::abs(id->getMappingInformation().getVoxelSize().y));
210
                float ratioRatio = sliceRatio / renderTargetRatio;
211
                cgt::mat4 viewMatrix = (ratioRatio > 1) ? cgt::mat4::createScale(cgt::vec3(1.f, 1.f / ratioRatio, 1.f)) : cgt::mat4::createScale(cgt::vec3(ratioRatio, 1.f, 1.f));
212

213 214
                cgt::mat4 scaleMatrix = cgt::mat4::createScale(cgt::vec3(_quadSize, 1.f));
                cgt::mat4 translation = cgt::mat4::createTranslation(cgt::vec3(_quadSize.x * x, _quadSize.y * y, 0.f));
215

216 217 218
                _paintShader->setUniform("_modelMatrix", translation * scaleMatrix * viewMatrix);

                // render texture
219
                paintTexture(id->getRepresentation<ImageRepresentationGL>()->getTexture(), unit2d, unit3d);
220 221 222 223 224 225 226 227
            }
        }

        _paintShader->deactivate();
        LGL_ERROR;
        glPopAttrib();
    }

228 229
    void DataContainerInspectorCanvas::paintTexture(const cgt::Texture* texture, const cgt::TextureUnit& unit2d, const cgt::TextureUnit& unit3d) {
        cgtAssert(texture != nullptr, "Texture to paint is 0. This should not happen!");
230 231
        if (texture == nullptr)
            return;
232 233

        _paintShader->setIgnoreUniformLocationError(true);
234
        if (texture->getType() == GL_TEXTURE_2D) {
235 236 237
            unit2d.activate();
            texture->bind();
            _paintShader->setUniform("_is3d", false);
238
            _paintShader->setUniform("_isDepthTexture", texture->isDepthTexture());
239 240
            _paintShader->setUniform("_2dTextureParams._size", cgt::vec2(texture->getDimensions().xy()));
            _paintShader->setUniform("_2dTextureParams._sizeRCP", cgt::vec2(1.f) / cgt::vec2(texture->getDimensions().xy()));
241
            _paintShader->setUniform("_2dTextureParams._numChannels", static_cast<int>(texture->getNumChannels()));
242
        }
243
        else if (texture->getType() == GL_TEXTURE_3D) {
244 245 246
            unit3d.activate();
            texture->bind();
            _paintShader->setUniform("_is3d", true);
247
            _paintShader->setUniform("_sliceNumber", p_currentSlice.getValue());
248 249
            _paintShader->setUniform("_3dTextureParams._size", cgt::vec3(texture->getDimensions()));
            _paintShader->setUniform("_3dTextureParams._sizeRCP", cgt::vec3(1.f) / cgt::vec3(texture->getDimensions()));
250
            _paintShader->setUniform("_3dTextureParams._numChannels", static_cast<int>(texture->getNumChannels()));
251
        }
252 253
        _paintShader->setIgnoreUniformLocationError(false);

254
        _quad->render(GL_TRIANGLE_FAN);
255 256 257
        LGL_ERROR;
    }

258
    void DataContainerInspectorCanvas::onInvalidated() {
259 260 261 262 263

		// Prevent drawing when the window is not yet exposed to the window manager
		QWindow* wnd = dynamic_cast<QWindow*>(window()->windowHandle());
		if (!wnd || !wnd->isExposed()) return;

264
        // only if inited
265
        if (_quad != 0 && _paintShader != 0 && this->isVisible()) {
266
			
267 268 269
            this->makeCurrent();
            paint();
            this->swap();
270
            // avoid recursive paints.
271 272 273 274 275 276 277
//             if (! cgt::GlContextManager::getRef().checkWhetherThisThreadHasAcquiredOpenGlContext()) {
//                 SimpleJobProc.enqueueJob(
//                     [this] () {
//                     cgt::GLContextScopedLock lock(this);
//                     paint();
//                 });
//             }
278
        }
279 280
    }

281
    void DataContainerInspectorCanvas::createQuad() {
282
        _quad = GeometryDataFactory::createQuad(cgt::vec3(0.f), cgt::vec3(1.f), cgt::vec3(0.f, 1.f, 0.f), cgt::vec3(1.f, 0.f, 0.f));
283 284
    }

285
    void DataContainerInspectorCanvas::repaint() {
286
        emit s_invalidated();
287 288
    }

289
    void DataContainerInspectorCanvas::sizeChanged(const cgt::ivec2& size) {
290
		    emit s_invalidated();
291 292
    }

293
    void DataContainerInspectorCanvas::mouseMoveEvent(cgt::MouseEvent* e)
294
    {
295
        if (e->modifiers() & cgt::Event::CTRL) {
296
            int texIndx = (e->y() / _quadSize.y) * _numTiles.x + (e->x() / _quadSize.x);
297
            if (texIndx < 0 || texIndx >= static_cast<int>(_textures.size()))
298 299
                return;

300
            auto id = _textures[texIndx].getData<ImageData>();
301
            const cgt::Texture* tex = id->getRepresentation<ImageRepresentationGL>()->getTexture();
302
            const ImageRepresentationLocal* localRep = id->getRepresentation<ImageRepresentationLocal>();
303
            cgt::svec2 imageSize = id->getSize().xy();
304

305
            cgt::vec2 lookupTexelFloat = cgt::vec2((e->coord() % _quadSize) * cgt::ivec2(imageSize)) / cgt::vec2(_quadSize);
306 307 308

            // compute transformation matrices
            float renderTargetRatio = static_cast<float>(_quadSize.x) / static_cast<float>(_quadSize.y);
309 310
            float sliceRatio = (static_cast<float>(id->getSize().x) * std::abs(id->getMappingInformation().getVoxelSize().x))
                / (static_cast<float>(id->getSize().y) * std::abs(id->getMappingInformation().getVoxelSize().y));
311 312
            float ratioRatio = sliceRatio / renderTargetRatio;

313
            lookupTexelFloat /= (ratioRatio > 1) ? cgt::vec2(1.f, 1.f / ratioRatio) : cgt::vec2(ratioRatio, 1.f);
314
            
315
            cgt::svec3 lookupTexel(lookupTexelFloat.x, imageSize.y - lookupTexelFloat.y, 0);
Jakob Weiss's avatar
Jakob Weiss committed
316
            if (lookupTexel.x < imageSize.x && lookupTexel.y < imageSize.y) {
317
                if (tex->isDepthTexture()) {
318
                    emit s_depthChanged(lookupTexel, localRep->getElementNormalized(lookupTexel, 0));
319
                }
320 321 322
                else {
                    if (tex->getDimensions().z != 1) {
                        if (p_currentSlice.getValue() >= 0 && p_currentSlice.getValue() < tex->getDimensions().z) {
323 324 325 326 327
                            lookupTexel.z = static_cast<size_t>(p_currentSlice.getValue());
                            cgt::vec4 texel(0.f);
                            for (size_t i = 0; i < id->getNumChannels(); ++i) {
                                texel[i] = localRep->getElementNormalized(lookupTexel, i);
                            }
328
                            emit s_colorChanged(lookupTexel, texel);
329 330 331
                        }
                    }
                    else if (tex->getDimensions().y != 1) {
332 333 334 335
                        cgt::vec4 texel(0.f);
                        for (size_t i = 0; i < id->getNumChannels(); ++i) {
                            texel[i] = localRep->getElementNormalized(lookupTexel, i);
                        }
336
                        emit s_colorChanged(lookupTexel, texel);
337
                    }
338
                }
339 340 341 342
            }
        }
        else {
            e->ignore();
343
        }
344 345
    }

346 347
    void DataContainerInspectorCanvas::onEvent(cgt::Event* e) {
        cgt::EventListener::onEvent(e);
348
        
349 350 351
        if (!e->isAccepted()) {
            _tcp.onEvent(e);
            _tcp.process(_localDataContainer);
352 353
            e->accept();
            _geometriesDirty = true;
354
			      emit s_invalidated();
355 356 357
        }
    }

358 359 360 361 362 363 364 365 366 367 368 369 370
    void DataContainerInspectorCanvas::onDataContainerChanged(const QString& key, QtDataHandle dh) {
        {
            tbb::mutex::scoped_lock lock(_localMutex);

            // check whether DataHandle is already existing
            std::map<QString, QtDataHandle>::iterator lb = _handles.lower_bound(key);
            if (lb == _handles.end() || lb->first != key) {
                // not existant -> do nothing
            }
            else {
                // existant -> replace
                lb->second = QtDataHandle(dh);
                // update _textures array
371
                _texturesDirty = true;
372 373
            }
        }
374 375

        if (_texturesDirty)
376
			    emit s_invalidated();
377 378 379 380 381 382 383 384 385
    }

    void DataContainerInspectorCanvas::setDataHandles(const std::vector< std::pair<QString, QtDataHandle> >& handles) {
        {
            tbb::mutex::scoped_lock lock(_localMutex);
            _handles.clear();
            for (std::vector< std::pair<QString, QtDataHandle> >::const_iterator it = handles.begin(); it != handles.end(); ++it)
                _handles.insert(*it);

386 387 388 389 390 391 392 393 394 395 396 397 398 399
            _localDataContainer.clear();
            _geometryNames.clear();

            // use LightSourceProvider processor to create lighting information.
            // This is needed to be done once after the local DataContainer got cleared.
            LightSourceProvider lsp;
            lsp.init();
            lsp.invalidate(AbstractProcessor::INVALID_RESULT);
            lsp.process(_localDataContainer);
            lsp.deinit();

            // reset trackball
            resetTrackball();

400
            _texturesDirty = true;
401 402
        }

403
		    emit s_invalidated();
404 405 406
    }

    void DataContainerInspectorCanvas::updateTextures() {
407
        /// Calculate the maximum slices of the textures and fill the textures array
408
        int maxSlices = 1;
409
        _textures.clear();
410
        p_viewportSize.setValue(cgt::ivec2(width(), height()));
411

412
        for (std::map<QString, QtDataHandle>::iterator it = _handles.begin(); it != _handles.end(); ++it) {
413
            if (auto img = it->second.getData<ImageData>()) {
414
                if (const ImageRepresentationGL* imgGL = img->getRepresentation<ImageRepresentationGL>()) {
415
                    _textures.push_back(it->second);
416
                    maxSlices = std::max(maxSlices, imgGL->getTexture()->getDimensions().z);
417 418
                }
            }
419
            else if (auto rd = it->second.getData<RenderData>()) {
420 421
                for (size_t i = 0; i < rd->getNumColorTextures(); ++i) {
                    const ImageRepresentationGL* imgGL = rd->getColorTexture(i)->getRepresentation<ImageRepresentationGL>();
422
                    if (imgGL) {
423
                        _textures.push_back(rd->getColorDataHandle(i));
424
                    }
425 426 427
                }
                if (rd->hasDepthTexture()) {
                    const ImageRepresentationGL* imgGL = rd->getDepthTexture()->getRepresentation<ImageRepresentationGL>();
428
                    if (imgGL) {
429
                        _textures.push_back(rd->getDepthDataHandle());
430
                    }
431 432 433

                }
            }
434
            else if (auto gd = it->second.getData<GeometryData>()) {
435
                std::string name = it->first.toStdString();
436 437

                // copy geometry over to local 
438
                _localDataContainer.addDataHandle(name + ".geometry", it->second);
439 440 441 442 443 444

                // render
                renderGeometryIntoTexture(name);

                // store name
                _geometryNames.push_back(std::make_pair(name, static_cast<int>(_textures.size()) - 1));
445
            }
446
        }
447 448

        if (maxSlices == 1)
Declara Denis's avatar
Declara Denis committed
449
            maxSlices = 0;
450
        p_currentSlice.setMaxValue(maxSlices - 1);
451
        _texturesDirty = false;
452
        _geometriesDirty = false;
453 454
    }

455

456
    void DataContainerInspectorCanvas::onPropertyChanged(const AbstractProperty* prop) {
457
        // ignore properties of the geometry renderer
458
        if (prop != &p_geometryRendererProperties)
459
			    emit s_invalidated();
460 461
    }

462
    void DataContainerInspectorCanvas::onGeometryRendererPropertyChanged(const AbstractProperty* prop) {
463
        _geometriesDirty = true;
464
		      emit s_invalidated();
465
    }
466

467 468
    void DataContainerInspectorCanvas::renderGeometryIntoTexture(const std::string& name, int textureIndex) {
        // setup GeometryRenderer
469 470 471
        _geometryRenderer.p_geometryID.setValue(name + ".geometry");
        _geometryRenderer.p_renderTargetID.setValue(name + ".rendered");
        _geometryRenderer.validate(AbstractProcessor::INVALID_PROPERTIES);
472
        _geometryRenderer.invalidate(AbstractProcessor::INVALID_RESULT);
473
        _geometryRenderer.process(_localDataContainer);
474 475 476 477 478 479 480 481 482 483 484 485 486 487

        // grab render result texture from local DataContainer and push into texture vector.
        ScopedTypedData<RenderData> rd(_localDataContainer, name + ".rendered");
        if (rd != nullptr && rd->getNumColorTextures() > 0) {
            auto rep = rd->getColorTexture(0)->getRepresentation<ImageRepresentationGL>();
            if (rep != nullptr) {
                if (textureIndex < 0 || textureIndex >= static_cast<int>(_textures.size())) {
                    _textures.push_back(rd->getColorDataHandle(0));
                }
                else {
                    _textures[textureIndex] = rd->getColorDataHandle(0);
                }
            }
            else {
488
                cgtAssert(false, "The rendered geometry does not have an OpenGL representation. Something went terribly wrong.");
489 490 491
            }
        }
        else {
492
            cgtAssert(false, "The rendered geometry does exist. Something went wrong.");
493 494
        }
    }
495
    
496 497
    void DataContainerInspectorCanvas::resetTrackball() {
        // check whether we have to render geometries
498
        cgt::Bounds unionBounds;
499
        for (std::map<QString, QtDataHandle>::iterator it = _handles.begin(); it != _handles.end(); ++it) {
500
            if (auto gd = it->second.getData<GeometryData>()) {
501 502 503 504 505 506
                unionBounds.addVolume(gd->getWorldBounds());
            }
        }

        // if so, create a new trackball
        if (unionBounds.isDefined()) {
507
            _tcp.reinitializeCamera(unionBounds);
508
        }
509 510 511

        _tcp.invalidate(AbstractProcessor::INVALID_RESULT);
        _tcp.process(_localDataContainer);
512
    }
513

514
}