Coin / src / engines / SoConcatenate.cpp

  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
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
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
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
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
262
263
264
265
266
267
268
269
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
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
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
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
/**************************************************************************\
 * Copyright (c) Kongsberg Oil & Gas Technologies AS
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * 
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * Neither the name of the copyright holder nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\**************************************************************************/

/*!
  \class SoConcatenate SoConcatenate.h Inventor/engines/SoConcatenate.h
  \brief The SoConcatenate class is used to concatenate several inputs into one output.
  \ingroup engines

  Takes all the values from the 10 input multivalue fields in turn and
  concatenates them into the multivalue output.


  Note that this engine's output field deviates a little from the
  "standard" output mechanism of the majority of engine classes: the
  SoConcatenate::output is not a permanent SoEngineOutput instance,
  but a \e pointer to a SoEngineOutput instance.  The reason for this
  is that it is necessary to allocate the output field dynamically to
  make it match what the SoConcatenate::input is connected to since
  the type of the SoConcatenate::output always should be the same as
  the type of the SoConcatenate::input.


  \ENGINE_TYPELESS_FILEFORMAT

  \verbatim
  Concatenate {
    type <multivaluefieldtype>
    [...fields...]
  }
  \endverbatim
*/

#include <Inventor/engines/SoConcatenate.h>

#include "SbBasicP.h"

#include <Inventor/SbString.h>
#include <Inventor/SoInput.h>
#include <Inventor/SoOutput.h>
#include <Inventor/errors/SoReadError.h>
#include <Inventor/lists/SoEngineOutputList.h>
#include <Inventor/fields/SoFields.h>

#if COIN_DEBUG
#include <Inventor/errors/SoDebugError.h>
#endif // COIN_DEBUG

#include "engines/SoSubEngineP.h"

/*!
  \var SoMField * SoConcatenate::input[10]
  The multivalue input fields which we will concatenate into the
  output.
*/
/*!
  \var SoEngineOutput * SoConcatenate::output

  (SoMField) This is the field output containing the concatenated
  values of all the input fields.

  The type of the field will of course match the type of the input
  field.
*/

// Can't use the standard SO_ENGINE_SOURCE macro, as this engine
// doesn't keep a class-global set of inputs and outputs: we need to
// make an instance of SoFieldData and SoEngineOutputData for every
// instance of the class, since the input and output fields are
// dynamically allocated.
SO_INTERNAL_ENGINE_SOURCE_DYNAMIC_IO(SoConcatenate);


/**************************************************************************/

// Default constructor. Leaves engine in invalid state. Should only be
// used from import code or copy code.
SoConcatenate::SoConcatenate(void)
{
  this->dynamicinput = NULL;
  this->dynamicoutput = NULL;
  for (int i=0; i < SoConcatenate::NUMINPUTS; i++) this->input[i] = NULL;
  this->output = NULL;
}

static SbBool
SoConcatenate_valid_type(SoType t)
{
  return (t.isDerivedFrom(SoMField::getClassTypeId()) &&
          t.canCreateInstance());
}


/*!
  Constructor. The type of the input/output is specified in \a type.
*/
SoConcatenate::SoConcatenate(SoType type)
{
  this->dynamicinput = NULL;
  this->dynamicoutput = NULL;
  for (int i=0; i < SoConcatenate::NUMINPUTS; i++) this->input[i] = NULL;
  this->output = NULL;

#if COIN_DEBUG
  if (!SoConcatenate_valid_type(type)) {
    SoDebugError::post("SoConcatenate::SoConcatenate",
                       "invalid type '%s' for input field, "
                       "field must be non-abstract and a multi-value type.",
                       type == SoType::badType() ? "badType" :
                       type.getName().getString());
  }
#endif // COIN_DEBUG

  this->initialize(type);
}


// doc from parent
void
SoConcatenate::initClass(void)
{
  SO_ENGINE_INTERNAL_INIT_CLASS(SoConcatenate);
}

// Set up the input and output fields of the engine. This is done from
// either the non-default constructor or the readInstance() import
// code.
void
SoConcatenate::initialize(const SoType inputfieldtype)
{
  assert(this->input[0] == NULL);
  assert(SoConcatenate_valid_type(inputfieldtype));

  SO_ENGINE_INTERNAL_CONSTRUCTOR(SoConcatenate);

  // Instead of SO_ENGINE_ADD_INPUT().
  this->dynamicinput = new SoFieldData(SoConcatenate::inputdata);
  for (int i=0; i < SoConcatenate::NUMINPUTS; i++) {
    this->input[i] = static_cast<SoMField *>(inputfieldtype.createInstance());
    this->input[i]->setNum(0);
    this->input[i]->setContainer(this);
    SbString s = "input";
    s.addIntString(i);
    this->dynamicinput->addField(this, s.getString(), this->input[i]);
  }

  // Instead of SO_ENGINE_ADD_OUTPUT().
  this->output = new SoEngineOutput;
  this->dynamicoutput = new SoEngineOutputData(SoConcatenate::outputdata);
  this->dynamicoutput->addOutput(this, "output", this->output, inputfieldtype);
  this->output->setContainer(this);
}

/*!
  Destructor.
*/
SoConcatenate::~SoConcatenate()
{
  delete this->dynamicinput;
  delete this->dynamicoutput;

  for (int i=0; i < SoConcatenate::NUMINPUTS; i++) delete this->input[i];
  delete this->output;
}

// Documented in superclass. Overridden to initialize type of input
// before reading.
SbBool
SoConcatenate::readInstance(SoInput * in, unsigned short flagsarg)
{
  // This code is identical to readInstance() of SoSelectOne and
  // SoGate, so migrate changes.

  SbName tmp;
  if (!in->read(tmp) || tmp != "type") {
    SoReadError::post(in,
                      "\"type\" keyword is missing, erroneous format for "
                      "engine class '%s'.",
                      this->getTypeId().getName().getString());
    return FALSE;
  }
  // need to use an SbString here, because SoInput::read( SbName & )
  // reads in '"MyName"' as is instead of as 'MyName'.
  SbString fieldname;
  if (!in->read(fieldname)) {
    SoReadError::post(in, "Couldn't read input type for engine.");
    return FALSE;
  }
  SoType inputtype = SoType::fromName(fieldname);
  if (!SoConcatenate_valid_type(inputtype)) {
    SoReadError::post(in, "Type \"%s\" for input field is not valid "
                      "(field must be non-abstract and a multi-value type).",
                      fieldname.getString());
    return FALSE;
  }

  this->initialize(inputtype);
  return SoEngine::readInstance(in, flagsarg);
}

// Documented in superclass. Overridden to write type of inputs.
void
SoConcatenate::writeInstance(SoOutput * out)
{
  // This code is identical to writeInstance() of SoSelectOne and
  // SoGate, so migrate changes.

  if (this->writeHeader(out, FALSE, TRUE)) return;

  SbBool binarywrite = out->isBinary();

  if (!binarywrite) out->indent();
  out->write("type");
  if (!binarywrite) out->write(' ');
  out->write(this->input[0]->getTypeId().getName());
  if (binarywrite) out->write(static_cast<unsigned int>(0));
  else out->write('\n');

  this->getFieldData()->write(out, this);
  this->writeFooter(out);
}

// Documented in superclass.
void
SoConcatenate::copyContents(const SoFieldContainer * from,
                            SbBool copyconnections)
{
  const SoConcatenate * concatenatesrc =
    coin_assert_cast<const SoConcatenate *>(from);
  if (concatenatesrc->input[0]) { this->initialize(concatenatesrc->input[0]->getTypeId()); }
  inherited::copyContents(from, copyconnections);
}

// Macro used to generate a function for the transfer of values from
// an SoMField to another (of the same type).
#define TRANSFER_FUNC(_fieldtype_) \
static void _fieldtype_##_transfer(SoMField * output, int outidx, SoMField * input) \
{ \
  _fieldtype_ * in = coin_assert_cast<_fieldtype_ *>(input); \
  assert(in != NULL); \
  coin_assert_cast<_fieldtype_ *>(output)->setValues(outidx, in->getNum(), in->getValues(0)); \
}

// Cover all known SoMField subclasses.
TRANSFER_FUNC(SoMFBitMask);
TRANSFER_FUNC(SoMFBool);
TRANSFER_FUNC(SoMFColor);
TRANSFER_FUNC(SoMFEngine);
TRANSFER_FUNC(SoMFEnum);
TRANSFER_FUNC(SoMFFloat);
TRANSFER_FUNC(SoMFInt32);
TRANSFER_FUNC(SoMFMatrix);
TRANSFER_FUNC(SoMFName);
TRANSFER_FUNC(SoMFNode);
TRANSFER_FUNC(SoMFPath);
TRANSFER_FUNC(SoMFPlane);
TRANSFER_FUNC(SoMFRotation);
TRANSFER_FUNC(SoMFShort);
TRANSFER_FUNC(SoMFString);
TRANSFER_FUNC(SoMFTime);
TRANSFER_FUNC(SoMFUInt32);
TRANSFER_FUNC(SoMFUShort);
TRANSFER_FUNC(SoMFVec2f);
TRANSFER_FUNC(SoMFVec3f);
TRANSFER_FUNC(SoMFVec4f);
#undef TRANSFER_FUNC

// documented in superclass
void
SoConcatenate::evaluate(void)
{
  // we can't use SO_ENGINE_OUTPUT here, so the functionality is
  // duplicated in the for-loops.

  int i;

  // we can do this check only once
  if (!this->output->isEnabled()) return;

  int inputstop = -1; // store the last field that has at least one value
  int numvalues = 0;  // store the total number of values
  for (i = 0; i < SoConcatenate::NUMINPUTS; i++) {
    int cnt = this->input[i]->getNum();
    if (cnt) {
      numvalues += cnt;
      inputstop = i;
    }
  }

  const int numconnections = this->output->getNumConnections();
  const SoType type = this->output->getConnectionType();

  for (i = 0; i < numconnections; i++) {
    SoMField * out = coin_assert_cast<SoMField *>((*this->output)[i]);
    if (!out->isReadOnly()) {
      int cnt = 0;
      out->setNum(numvalues);
      for (int j = 0; j <= inputstop; j++) {
        SoMField * in = coin_assert_cast<SoMField *>(input[j]);

        if (type == SoMFBitMask::getClassTypeId()) {
          // (Seems safer to use SoMFBitMask's own methods, and not
          // from the superclass SoMFEnum, even though that may be
          // valid.)
          SoMFBitMask_transfer(out, cnt, in);
        }
        else if (type == SoMFBool::getClassTypeId()) {
          SoMFBool_transfer(out, cnt, in);
        }
        else if (type == SoMFColor::getClassTypeId()) {
          SoMFColor_transfer(out, cnt, in);
        }
        else if (type == SoMFEngine::getClassTypeId()) {
          SoMFEngine_transfer(out, cnt, in);
        }
        else if (type == SoMFEnum::getClassTypeId()) {
          SoMFEnum_transfer(out, cnt, in);
        }
        else if (type == SoMFFloat::getClassTypeId()) {
          SoMFFloat_transfer(out, cnt, in);
        }
        else if (type == SoMFInt32::getClassTypeId()) {
          SoMFInt32_transfer(out, cnt, in);
        }
        else if (type == SoMFMatrix::getClassTypeId()) {
          SoMFMatrix_transfer(out, cnt, in);
        }
        else if (type == SoMFName::getClassTypeId()) {
          SoMFName_transfer(out, cnt, in);
        }
        else if (type == SoMFNode::getClassTypeId()) {
          SoMFNode_transfer(out, cnt, in);
        }
        else if (type == SoMFPath::getClassTypeId()) {
          SoMFPath_transfer(out, cnt, in);
        }
        else if (type == SoMFPlane::getClassTypeId()) {
          SoMFPlane_transfer(out, cnt, in);
        }
        else if (type == SoMFRotation::getClassTypeId()) {
          SoMFRotation_transfer(out, cnt, in);
        }
        else if (type == SoMFShort::getClassTypeId()) {
          SoMFShort_transfer(out, cnt, in);
        }
        else if (type == SoMFString::getClassTypeId()) {
          SoMFString_transfer(out, cnt, in);
        }
        else if (type == SoMFTime::getClassTypeId()) {
          SoMFTime_transfer(out, cnt, in);
        }
        else if (type == SoMFUInt32::getClassTypeId()) {
          SoMFUInt32_transfer(out, cnt, in);
        }
        else if (type == SoMFUShort::getClassTypeId()) {
          SoMFUShort_transfer(out, cnt, in);
        }
        else if (type == SoMFVec2f::getClassTypeId()) {
          SoMFVec2f_transfer(out, cnt, in);
        }
        else if (type == SoMFVec3f::getClassTypeId()) {
          SoMFVec3f_transfer(out, cnt, in);
        }
        else if (type == SoMFVec4f::getClassTypeId()) {
          SoMFVec4f_transfer(out, cnt, in);
        }
        else {
          // Slower fallback (copying by going through string
          // conversion and deconversion), in case of new
          // (user-defined) field types.
          const int num = in->getNum();
          SbString strval;
          for (int k = 0; k < num; k++) {
            in->get1(k, strval);
            out->set1(cnt + k, strval.getString());
          }
        }

        cnt += in->getNum();
      }
    }
  }
}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.