matrixprocessor.cpp 15.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// ================================================================================================
// 
// This file is part of the CAMPVis Software Framework.
// 
// If not explicitly stated otherwise: Copyright (C) 2012-2014, all rights reserved,
//      Christian Schulte zu Berge <christian.szb@in.tum.de>
//      Chair for Computer Aided Medical Procedures
//      Technische Universitaet Muenchen
//      Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
// 
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
// 
// 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
// 
// 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.
// 
// ================================================================================================

#include "matrixprocessor.h"

#include "core/datastructures/imagedata.h"
#include "core/datastructures/genericimagerepresentationlocal.h"
#include "core/tools/stringutils.h"

31
#include "core/datastructures/transformdata.h"
32
33
34
35

namespace campvis {
    const std::string MatrixProcessor::loggerCat_ = "CAMPVis.modules.core.MatrixProcessor";

Jakob Weiss's avatar
Jakob Weiss committed
36
37
38
39
40
41
42
    GenericOption<std::string> typeOptions[2] = {
        GenericOption<std::string>("fixed", "Fixed Matrix"),
        GenericOption<std::string>("data", "Matrix from Data Container")
    };

    MatrixProcessor::MatrixProcessor()
        : AbstractProcessor()
43
44
        , p_parserMode("parsermode", "Enable Parser Mode (Experimental!)", false)
        , p_parserInputString("parserInput", "Parser Input")
Jakob Weiss's avatar
Jakob Weiss committed
45
46
47
48
49
50
51
52
        , p_matrixAType("MatrixA_Type", "Matrix A Source", typeOptions, 2)
        , p_matrixAID("MatrixA_ID", "Matrix A", "matrixA", DataNameProperty::READ)
        , p_matrixAString("MatrixA_String", "Matrix A String", "identity")
        , p_matrixAModifiers("MatrixAModifiers", "Matrix A Modifiers")
        , p_matrixBType("MatrixB_Type", "Matrix B Source", typeOptions, 2)
        , p_matrixBID("MatrixB_ID", "Matrix B", "matrixB", DataNameProperty::READ)
        , p_matrixBString("MatrixB_String", "Matrix B String", "identity")
        , p_matrixBModifiers("MatrixBModifiers", "Matrix B Modifiers")
Jakob Weiss's avatar
Jakob Weiss committed
53
        , p_targetMatrixID("TargetMatrixID", "Target Matrix ID", "ProbeToReference", DataNameProperty::WRITE)
54
        , p_cameraProperty("Camera", "Exported Camera")
Jakob Weiss's avatar
Jakob Weiss committed
55
        , _lastdc(nullptr)
56
    {
57
        addProperty(p_parserMode, INVALID_PROPERTIES);
58
        addProperty(p_parserInputString, INVALID_PROPERTIES | INVALID_RESULT);
59

Jakob Weiss's avatar
Jakob Weiss committed
60
61
62
63
        addProperty(p_matrixAType, INVALID_PROPERTIES | INVALID_RESULT);
        addProperty(p_matrixAID, INVALID_RESULT);
        addProperty(p_matrixAString, INVALID_RESULT);
        addProperty(p_matrixAModifiers, INVALID_RESULT);
Jakob Weiss's avatar
Jakob Weiss committed
64

Jakob Weiss's avatar
Jakob Weiss committed
65
66
67
68
        addProperty(p_matrixBType, INVALID_PROPERTIES | INVALID_RESULT);
        addProperty(p_matrixBID, INVALID_RESULT);
        addProperty(p_matrixBString, INVALID_RESULT);
        addProperty(p_matrixBModifiers, INVALID_RESULT);
Jakob Weiss's avatar
Jakob Weiss committed
69

Jakob Weiss's avatar
Jakob Weiss committed
70
        addProperty(p_targetMatrixID, INVALID_RESULT);
71

72
73
        addProperty(p_cameraProperty, VALID);

Jakob Weiss's avatar
Jakob Weiss committed
74
        invalidate(INVALID_PROPERTIES);
75
76
    }

Jakob Weiss's avatar
Jakob Weiss committed
77
78
79
    MatrixProcessor::~MatrixProcessor() {
        if (_lastdc)
            _lastdc->s_dataAdded.disconnect(this);
80
81
    }

Jakob Weiss's avatar
Jakob Weiss committed
82
83
    void MatrixProcessor::init() {

84
85
    }

Jakob Weiss's avatar
Jakob Weiss committed
86
87
    void MatrixProcessor::deinit() {

88
89
    }

Jakob Weiss's avatar
Jakob Weiss committed
90
    void MatrixProcessor::updateResult(DataContainer& data) {
Jakob Weiss's avatar
Jakob Weiss committed
91
#ifdef MATRIX_PROCESSOR_DEBUGGING
Jakob Weiss's avatar
Jakob Weiss committed
92
        LINFO("Updating Result");
Jakob Weiss's avatar
Jakob Weiss committed
93
#endif
Jakob Weiss's avatar
Jakob Weiss committed
94

Jakob Weiss's avatar
Jakob Weiss committed
95
96
97
98
        if (&data != _lastdc) {
            if (_lastdc) {
                _lastdc->s_dataAdded.disconnect(this);
            }
99

Jakob Weiss's avatar
Jakob Weiss committed
100
101
102
            data.s_dataAdded.connect(this, &MatrixProcessor::DataContainerDataAdded);
            _lastdc = &data;
        }
103

104
105
        if (p_parserMode.getValue()) {
            parseString(p_parserInputString.getValue(), data);
Jakob Weiss's avatar
Jakob Weiss committed
106
107
        }
        else {
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
            tgt::mat4 matA = tgt::mat4::createIdentity();
            if (p_matrixAType.getOptionValue() == "fixed")
                matA = processMatrixString(p_matrixAString.getValue(), data);
            else {
                ScopedTypedData<TransformData> td(data, p_matrixAID.getValue());
                if (td != 0) matA = td->getTransform();
            }

            tgt::mat4 matB = tgt::mat4::createIdentity();
            if (p_matrixBType.getOptionValue() == "fixed")
                matB = processMatrixString(p_matrixBString.getValue(), data);
            else {
                ScopedTypedData<TransformData> td(data, p_matrixBID.getValue());
                if (td != 0) matB = td->getTransform();
            }
123

124
125
            tgt::mat4 matAProcessed = processModifierString(matA, p_matrixAModifiers.getValue());
            tgt::mat4 matBProcessed = processModifierString(matB, p_matrixBModifiers.getValue());
126
127


128
            tgt::mat4 result = matAProcessed * matBProcessed;
129

Jakob Weiss's avatar
Jakob Weiss committed
130
#ifdef MATRIX_PROCESSOR_DEBUGGING
131
132
133
134
135
136
            LDEBUG("Matrix A: " << std::endl << matA);
            LDEBUG("Matrix A':" << std::endl << matAProcessed);
            LDEBUG("Matrix B: " << std::endl << matB);
            LDEBUG("Matrix B':" << std::endl << matBProcessed);
            LDEBUG("Result Matrix: " << std::endl << result);
            LDEBUG(std::endl);
Jakob Weiss's avatar
Jakob Weiss committed
137
#endif
138

139
            TransformData * td = new TransformData(result);
Jakob Weiss's avatar
Jakob Weiss committed
140

141
142
            data.addData(p_targetMatrixID.getValue(), td);
        }
143
144
145
146

        validate(INVALID_RESULT);
    }

Jakob Weiss's avatar
Jakob Weiss committed
147
148
    void MatrixProcessor::updateProperties(DataContainer& dataContainer)
    {
Jakob Weiss's avatar
Jakob Weiss committed
149
#ifdef MATRIX_PROCESSOR_DEBUGGING
Jakob Weiss's avatar
Jakob Weiss committed
150
        LINFO("Updating Properties");
Jakob Weiss's avatar
Jakob Weiss committed
151
#endif
152
153
        bool pmode = p_parserMode.getValue();
        p_parserInputString.setVisible(pmode);
Jakob Weiss's avatar
Jakob Weiss committed
154

155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
        p_matrixAType.setVisible(!pmode);
        p_matrixAID.setVisible(!pmode);
        p_matrixAString.setVisible(!pmode);
        p_matrixAModifiers.setVisible(!pmode);

        p_matrixBType.setVisible(!pmode);
        p_matrixBID.setVisible(!pmode);
        p_matrixBString.setVisible(!pmode);
        p_matrixBModifiers.setVisible(!pmode);

        p_targetMatrixID.setVisible(!pmode);

        if(!pmode) {
            if (p_matrixAType.getOptionValue() == "fixed") {
                p_matrixAID.setVisible(false);
                p_matrixAString.setVisible(true);
            }
            else {
                p_matrixAID.setVisible(true);
                p_matrixAString.setVisible(false);
            }

            if (p_matrixBType.getOptionValue() == "fixed") {
                p_matrixBID.setVisible(false);
                p_matrixBString.setVisible(true);
            }
            else {
                p_matrixBID.setVisible(true);
                p_matrixBString.setVisible(false);
            }
Jakob Weiss's avatar
Jakob Weiss committed
185
186
        }

187
188
189
190
191
        //update the data name dependencies
        _dataDependencies.clear();
        auto l1 = StringUtils::split(p_parserInputString.getValue(), "[");
        for (size_t i = 1, s = l1.size(); i < s; ++i) {
            auto l2 = StringUtils::split(l1[i], "]");
192
            //LDEBUG("Data Name: " << l2[0]);
193
194
195
            _dataDependencies.insert(l2[0]);
        }

Jakob Weiss's avatar
Jakob Weiss committed
196
197
198
        validate(INVALID_PROPERTIES);
    }

199
    tgt::mat4 MatrixProcessor::processMatrixString(std::string matrixString, DataContainer& data, std::map<std::string, tgt::mat4> *localDefs)
Jakob Weiss's avatar
Jakob Weiss committed
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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
    {
        std::vector<std::string> tokens = StringUtils::split(matrixString, " ");

        if (tokens.size() == 0 || tokens[0] == "identity") {
            return tgt::mat4(tgt::mat4::identity);
        }
        // if we have exactly 16 tokens, we assume we have a matrix in numerical form
        else if (tokens.size() == 16) {
            tgt::mat4 mat;
            float * p = mat.elem;
            for (int i = 0; i < 16; i++) {
                *p = static_cast<float>(atof(tokens[i].c_str()));
                p++;
            }
            return mat;
        }
        // if the first token is "rot", we create an angle axis rotation matrix with the specified arguments
        else if (tokens[0] == "rot") {
            if (tokens.size() != 5) {
                LWARNING("Rotation matrix string does not have the correct number of arguments!");
                return tgt::mat4::createIdentity();
            }
            float angle;
            tgt::vec3 axis;
            angle = static_cast<float>(atof(tokens[1].c_str()));
            axis[0] = static_cast<float>(atof(tokens[2].c_str()));
            axis[1] = static_cast<float>(atof(tokens[3].c_str()));
            axis[2] = static_cast<float>(atof(tokens[4].c_str()));
            return tgt::mat4::createRotation(angle, axis);
        }
        else if (tokens[0] == "trans") {
            if (tokens.size() != 4) {
                LWARNING("Translation matrix string does not have the correct number of arguments!");
                return tgt::mat4::createIdentity();
            }

            tgt::vec3 translation;
            translation[0] = static_cast<float>(atof(tokens[1].c_str()));
            translation[1] = static_cast<float>(atof(tokens[2].c_str()));
            translation[2] = static_cast<float>(atof(tokens[3].c_str()));
            return tgt::mat4::createTranslation(translation);
        }
        else if (tokens[0] == "scale") {
            if (tokens.size() != 2 && tokens.size() != 4) {
                LWARNING("Scaling matrix string does not have the correct number of arguments!");
                return tgt::mat4::createIdentity();
            }

            tgt::vec3 scale;
            scale[0] = static_cast<float>(atof(tokens[1].c_str()));
            if (tokens.size() == 4) {
                scale[1] = static_cast<float>(atof(tokens[2].c_str()));
                scale[2] = static_cast<float>(atof(tokens[3].c_str()));
            }
            else {
                scale[1] = scale[2] = scale[0];
            }

            return tgt::mat4::createScale(scale);
        }
        // if we cannot find another pattern, we assume we have a data container ID
        else {
262
263
264
265
266
267
268
269
            // see if we can find the matrix in the local definitions
            if (localDefs) {
                auto pos = localDefs->find(matrixString);
                if (pos != localDefs->end()) {
                    return pos->second;
                }
            }

Jakob Weiss's avatar
Jakob Weiss committed
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
            ScopedTypedData<TransformData> td(data, matrixString);
            if (td == 0) {
                LWARNING("Data Container ID \"" << matrixString << "\" was not suitable as input Matrix");
                return tgt::mat4::createIdentity();
            }

            return td->getTransform();
        }

    }

    tgt::mat4 MatrixProcessor::processModifierString(tgt::mat4 matrix, std::string modifiers)
    {
        int pos = 0;
        tgt::mat4 result = matrix, tmp;

        while (pos < modifiers.size())
        {
            switch (modifiers[pos]) {
            case 'I':
                if (!result.invert(tmp)) {
                    LWARNING("Matrix Inversion failed.");
                }
                else result = tmp;
                break;
            case 'T':
                result = tgt::transpose(result);
                break;
            case '-':
                result = tgt::mat4::zero - result;
                break;
            case 'r':
                result = result.getRotationalPart();
                break;
            case 's':
                result = tgt::mat4::createScale(result.getScalingPart());
                break;
            default:
                LWARNING("Ignoring unknown modifier: " << modifiers[pos]);
            }
310
            ++pos;
Jakob Weiss's avatar
Jakob Weiss committed
311
312
313
314
        }
        return result;
    }

315
316
317
318
319
320
321
322
323
324

    void MatrixProcessor::parseString(const std::string & parserInput, DataContainer & dc)
    {
        std::map<std::string, tgt::mat4> results;

        std::vector<std::string> equations = StringUtils::split(parserInput, ";");

        //evaluate every assignment
        for (size_t i = 0, nEq = equations.size(); i != nEq; ++i)
        {
325
            std::string eqn = campvis::StringUtils::trim(equations[i]);
326
327
328
329
330
331
332
333
334
335
336
337
            try {
                //skip empty equations
                if (!eqn.size()) continue;

                //LDEBUG("Equation: " << eqn);

                size_t equal_pos = eqn.find('=', 0);
                if (equal_pos == std::string::npos) {
                    LWARNING("No equal sign in equation \"" << eqn << "\". Skipping this assignment.");
                    continue;
                }

338
339
                std::string assignedMatName = campvis::StringUtils::trim(eqn.substr(0, equal_pos));
                std::string formulaToEvaluate = campvis::StringUtils::trim(eqn.substr(equal_pos + 1, std::string::npos));
340
341
342
343
344
345
346
                //LDEBUG("Matrix Name: " << assignedMatName << ". Formula: " << formulaToEvaluate);

                //split formulaToEvaluate by the multiplications
                tgt::mat4 assignedResult = tgt::mat4::identity;
                std::vector<std::string> multiplicands = StringUtils::split(formulaToEvaluate, "*");
                for (size_t m = 0, nMul = multiplicands.size(); m != nMul; ++m)
                {
347
                    std::string matStrCombined = campvis::StringUtils::trim(multiplicands[m]);
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
                    //parse multiplicands of form "[<MatrixString>]_<Modifiers>"
                    size_t delimPos = matStrCombined.find("]");

                    if (!(matStrCombined[0] == '[') || delimPos == std::string::npos) {
                        LWARNING("Error parsing matrix part \"" << matStrCombined << "\": Delimiters not found! Ignoring multiplicand..");
                        continue;
                    }

                    std::string matStr = matStrCombined.substr(1, delimPos - 1);
                    std::string modifiers = delimPos + 2 > matStrCombined.size() ? ""
                        : matStrCombined.substr(delimPos + 2, std::string::npos);
                    //LDEBUG("Matrix String: " << matStr << " Modifiers: " << modifiers);

                    //evaluate matrix and and multiply to the result
                    tgt::mat4 multiplicand = processMatrixString(matStr, dc, &results);
                    assignedResult *= processModifierString(multiplicand, modifiers);
                }

                //save result into result map
                results[assignedMatName] = assignedResult;
            }
            catch (std::exception &e) {
                LWARNING("Exception while parsing equation \"" << eqn << "\": " << e.what());
            }
        }

        // put all results into the data container
        // matrix names beginning with an underscore are skipped
376
        // _camera matrix is used to modify m_cameraProperty
377
378
379
380
        for (auto it = results.begin(), end = results.end(); it != end; ++it) {
            if (it->first[0] != '_') {
                dc.addData(it->first, new TransformData(it->second));
            }
381
382
383
384
385
            if (it->first == "_camera") {
                tgt::Camera cam = p_cameraProperty.getValue();
                cam.setViewMatrix(it->second);
                p_cameraProperty.setValue(cam);
            }
386
387
388
        }
    }

Jakob Weiss's avatar
Jakob Weiss committed
389
390
    void MatrixProcessor::DataContainerDataAdded(const std::string &name, const DataHandle &data)
    {
391
392
393
394
395
396
397
398
        if (p_parserMode.getValue()) {
            if (_dataDependencies.find(name) != _dataDependencies.end())
                invalidate(INVALID_RESULT);
        }
        else {
            if (name == p_matrixAID.getValue() || name == p_matrixBID.getValue())
                invalidate(INVALID_RESULT);
        }
Jakob Weiss's avatar
Jakob Weiss committed
399
    }
400
}