Starting from 2021-07-01, all LRZ GitLab users will be required to explicitly accept the GitLab Terms of Service. Please see the detailed information at https://doku.lrz.de/display/PUBLIC/GitLab and make sure that your projects conform to the requirements.

autoevaluationpipeline.cpp 10.5 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-2014, 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
#include "autoevaluationpipeline.h"
26

27
#include "cgt/cgt_gl.h"
28
#include "cgt/glcanvas.h"
29

30
#include "core/pipeline/visualizationprocessor.h"
31
#include "core/properties/datanameproperty.h"
32
#include "core/properties/metaproperty.h"
33

schultezub's avatar
schultezub committed
34
namespace campvis {
35
    const std::string AutoEvaluationPipeline::loggerCat_ = "CAMPVis.core.datastructures.AutoEvaluationPipeline";
36

37 38
    AutoEvaluationPipeline::AutoEvaluationPipeline(DataContainer* dc) 
        : AbstractPipeline(dc)
39 40 41
    {
    }

42
    AutoEvaluationPipeline::~AutoEvaluationPipeline() {
43 44
    }

45
    void AutoEvaluationPipeline::init() {
46
        AbstractPipeline::init();
schultezub's avatar
schultezub committed
47

48 49 50
        // connect invalidation of each processor
        for (std::vector<AbstractProcessor*>::iterator it = _processors.begin(); it != _processors.end(); ++it) {
            (*it)->s_invalidated.connect(this, &AutoEvaluationPipeline::onProcessorInvalidated);
schultezub's avatar
schultezub committed
51
        }
52 53

        _data->s_dataAdded.connect(this, &AutoEvaluationPipeline::onDataContainerDataAdded);
54 55
    }

56
    void AutoEvaluationPipeline::deinit() {
57 58
        _data->s_dataAdded.disconnect(this);

59 60
        for (std::vector<AbstractProcessor*>::iterator it = _processors.begin(); it != _processors.end(); ++it) {
            (*it)->s_invalidated.disconnect(this);
61
        }
62 63
    
        AbstractPipeline::deinit();
64 65
    }

66
    void AutoEvaluationPipeline::onProcessorInvalidated(AbstractProcessor* processor) {
67
        if (_canvas == nullptr || getEnabled() == false)
68 69
            return;

70
        setPipelineDirty();
71 72
    }

73
    void AutoEvaluationPipeline::addProcessor(AbstractProcessor* processor) {
74
        _isVisProcessorMap.insert(std::make_pair(processor, (dynamic_cast<VisualizationProcessor*>(processor) != 0)));
75
        findDataNamePropertiesAndAddToPortMap(processor);
76

77 78 79
        AbstractPipeline::addProcessor(processor);
    }

80
    void AutoEvaluationPipeline::executePipeline() {
81 82
        // execute each processor once 
        // (AbstractProcessor::process() takes care of executing only invalid processors)
83
        for (size_t i = 0; i < _processors.size(); ++i) {
84
            executeProcessorAndCheckOpenGLState(_processors[i]);
85 86 87
        }
    }

88
    void AutoEvaluationPipeline::onDataNamePropertyChanged(const AbstractProperty* prop) {
89 90
        // static_cast is safe since this slot only get called for DataNameProperties
        // const_cast is not beautiful but safe here as well
91 92
        DataNameProperty* dnp = const_cast<DataNameProperty*>(static_cast<const DataNameProperty*>(prop));

93
        // find string-iterator pair for the given property
94 95
        IteratorMapType::iterator it = _iteratorMap.find(dnp);
        if (it != _iteratorMap.end()) {
96 97
            // check whether the value of the DataNameProperty differs from the one in our port map
            // i.e.: We need to update the port map
98 99
            if (dnp->getValue() != it->second->first) {
                {
100
                    // acquire a write-lock since we erase the old value from our port map
101 102 103 104
                    tbb::spin_rw_mutex::scoped_lock lock(_pmMutex, true);
                    _portMap.unsafe_erase(it->second);
                }

105
                // acquire read-lock since we add the new value to the port map
106
                tbb::spin_rw_mutex::scoped_lock lock(_pmMutex, false);
107 108

                // insert new value into port map and update the reference in the iterator map
109 110 111 112
                std::pair<PortMapType::iterator, bool> result = _portMap.insert(std::make_pair(dnp->getValue(), dnp));
                if (result.second) {
                    it->second = result.first;
                }
113 114

                // sanity check, if this assertion fails, we have a problem...
115
                cgtAssert(result.second, "Could not insert Property into port map!");
116 117 118
            }
        }
        else {
119
            // this should not happen, otherwise we did something wrong before.
120
            cgtAssert(false, "Could not find Property in iterator map!");
121 122 123
        }
    }

124 125 126 127 128 129 130 131 132 133 134
    namespace {
        /// Local helper function to recursively emit the s_changed signal for the given
        /// properties and all of its shared properties.
        void recursiveEmitSignal(DataNameProperty* p) {
            std::set<AbstractProperty*> v = p->getSharedProperties();
            for (auto it = v.begin(); it != v.end(); ++it)
                recursiveEmitSignal(static_cast<DataNameProperty*>(*it));
            p->s_changed.emitSignal(p);
        }
    }

135
    void AutoEvaluationPipeline::onDataContainerDataAdded(std::string name, DataHandle dh) {
136
        {
137
            // acquire read lock
138
            tbb::spin_rw_mutex::scoped_lock lock(_pmMutex, false);
139 140

            // find all DataNameProperties in the port map that have name as current value
141
            PortMapType::const_iterator it = _portMap.find(name);
142 143
            while (it != _portMap.end() && it->first == name) {
                // invalidate those properties by emitting changed signal
144
                recursiveEmitSignal(it->second);
145 146 147 148 149
                ++it;
            }
        }
    }

150 151 152
    void AutoEvaluationPipeline::findDataNamePropertiesAndAddToPortMap(const HasPropertyCollection* hpc) {
        const PropertyCollection& pc = hpc->getProperties();

153 154 155 156
        // const_cast okay, since we're just connecting to signals
        const_cast<HasPropertyCollection*>(hpc)->s_propertyAdded.connect(this, &AutoEvaluationPipeline::onPropertyCollectionPropertyAdded);
        const_cast<HasPropertyCollection*>(hpc)->s_propertyRemoved.connect(this, &AutoEvaluationPipeline::onPropertyCollectionPropertyRemoved);

157 158 159 160 161 162 163
        // traverse property collection
        for (size_t i = 0; i < pc.size(); ++i) {
            if (DataNameProperty* dnp = dynamic_cast<DataNameProperty*>(pc[i])) {
                // if DataNameProperty, add to port map and register to changed signal
                if (dnp->getAccessInfo() == DataNameProperty::READ) {
                    tbb::spin_rw_mutex::scoped_lock lock(_pmMutex, false);
                    std::pair<PortMapType::iterator, bool> result = _portMap.insert(std::make_pair(dnp->getValue(), dnp));
164
                    cgtAssert(result.second, "Could not insert Property into port map!");
165 166 167 168 169 170 171 172 173 174 175 176 177
                    if (result.second) {
                        _iteratorMap[dnp] = result.first;
                        dnp->s_changed.connect(this, &AutoEvaluationPipeline::onDataNamePropertyChanged);
                    }
                }
            }
            else if (MetaProperty* mp = dynamic_cast<MetaProperty*>(pc[i])) {
                // if MetaProperty, recursively check its PropertyCollection
                findDataNamePropertiesAndAddToPortMap(mp);
            }
        }
    }

178 179 180
    void AutoEvaluationPipeline::onPropertyCollectionPropertyAdded(AbstractProperty* property) {
        // check whether the incoming property is of the correct type (we only care about DataNameProperties)
        if (DataNameProperty* dnp = dynamic_cast<DataNameProperty*>(property)) {
Christian Schulte zu Berge's avatar
Christian Schulte zu Berge committed
181 182 183 184 185
            if (dnp->getAccessInfo() == DataNameProperty::READ) {
                // check whether this property is already present in the port map
                IteratorMapType::iterator it = _iteratorMap.find(dnp);
                if (it == _iteratorMap.end()) {
                    // add to port map and register to changed signal
186 187 188 189 190 191 192 193
                    tbb::spin_rw_mutex::scoped_lock lock(_pmMutex, false);
                    std::pair<PortMapType::iterator, bool> result = _portMap.insert(std::make_pair(dnp->getValue(), dnp));
                    cgtAssert(result.second, "Could not insert Property into port map!");
                    if (result.second) {
                        _iteratorMap[dnp] = result.first;
                        dnp->s_changed.connect(this, &AutoEvaluationPipeline::onDataNamePropertyChanged);
                    }
                }
Christian Schulte zu Berge's avatar
Christian Schulte zu Berge committed
194 195 196 197
                else {
                    // this should not happen, otherwise we did something wrong before.
                    cgtAssert(false, "This property is already in iterator map!");
                }
198 199 200 201 202 203 204
            }
        }
    }

    void AutoEvaluationPipeline::onPropertyCollectionPropertyRemoved(AbstractProperty* property) {
        // check whether the incoming property is of the correct type (we only care about DataNameProperties)
        if (DataNameProperty* dnp = dynamic_cast<DataNameProperty*>(property)) {
Christian Schulte zu Berge's avatar
Christian Schulte zu Berge committed
205 206 207 208
            if (dnp->getAccessInfo() == DataNameProperty::READ) {
                // find string-iterator pair for the given property
                IteratorMapType::iterator it = _iteratorMap.find(dnp);
                if (it != _iteratorMap.end()) {
209 210 211 212 213 214 215 216 217 218
                    // remove from port map and deregister from changed signal
                    dnp->s_changed.disconnect(this);

                    // acquire a write-lock since we erase the old value from our port map
                    tbb::spin_rw_mutex::scoped_lock lock(_pmMutex, true);

                    // remove the property from the port map
                    _portMap.unsafe_erase(it->second);
                    _iteratorMap.unsafe_erase(it);
                }
Christian Schulte zu Berge's avatar
Christian Schulte zu Berge committed
219 220 221 222
                else {
                    // this should not happen, otherwise we did something wrong before.
                    cgtAssert(false, "Could not find Property in iterator map!");
                }
223 224 225 226
            }
        }
    }

227
}