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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
    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)) {
            // 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
                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));
                    cgtAssert(result.second, "Could not insert Property into port map!");
                    if (result.second) {
                        _iteratorMap[dnp] = result.first;
                        dnp->s_changed.connect(this, &AutoEvaluationPipeline::onDataNamePropertyChanged);
                    }
                }

            }
            else {
                // this should not happen, otherwise we did something wrong before.
                cgtAssert(false, "This property is already in iterator map!");
            }
        }

    }

    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)) {
            // find string-iterator pair for the given property
            IteratorMapType::iterator it = _iteratorMap.find(dnp);
            if (it != _iteratorMap.end()) {
                if (dnp->getAccessInfo() == DataNameProperty::READ) {
                    // 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);
                }
            }
            else {
                // this should not happen, otherwise we did something wrong before.
                cgtAssert(false, "Could not find Property in iterator map!");
            }
        }
    }

230
}