Coverage Report

Created: 2025-07-11 06:05

/src/alembic/lib/Alembic/AbcGeom/XformOp.cpp
Line
Count
Source (jump to first uncovered line)
1
//-*****************************************************************************
2
//
3
// Copyright (c) 2009-2012,
4
//  Sony Pictures Imageworks, Inc. and
5
//  Industrial Light & Magic, a division of Lucasfilm Entertainment Company Ltd.
6
//
7
// All rights reserved.
8
//
9
// Redistribution and use in source and binary forms, with or without
10
// modification, are permitted provided that the following conditions are
11
// met:
12
// *       Redistributions of source code must retain the above copyright
13
// notice, this list of conditions and the following disclaimer.
14
// *       Redistributions in binary form must reproduce the above
15
// copyright notice, this list of conditions and the following disclaimer
16
// in the documentation and/or other materials provided with the
17
// distribution.
18
// *       Neither the name of Sony Pictures Imageworks, nor
19
// Industrial Light & Magic nor the names of their contributors may be used
20
// to endorse or promote products derived from this software without specific
21
// prior written permission.
22
//
23
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
//
35
//-*****************************************************************************
36
37
#include <Alembic/AbcGeom/XformOp.h>
38
39
namespace Alembic {
40
namespace AbcGeom {
41
namespace ALEMBIC_VERSION_NS {
42
43
//-*****************************************************************************
44
XformOp::XformOp()
45
0
  : m_type( kTranslateOperation )
46
0
  , m_hint( 0 )
47
0
{
48
0
    m_channels.clear();
49
0
    m_channels.resize( 3 );
50
0
}
51
52
//-*****************************************************************************
53
XformOp::XformOp( const XformOperationType iType,
54
                  const Alembic::Util::uint8_t iHint )
55
0
    : m_type( iType )
56
0
{
57
0
    m_channels.clear();
58
59
0
    switch ( m_type )
60
0
    {
61
0
    case kRotateXOperation:
62
0
    case kRotateYOperation:
63
0
    case kRotateZOperation:
64
0
        m_channels.resize( 1 );
65
0
        break;
66
0
    case kScaleOperation:
67
0
    case kTranslateOperation:
68
0
        m_channels.resize( 3 );
69
0
        break;
70
0
    case kRotateOperation:
71
0
        m_channels.resize( 4 );
72
0
        break;
73
0
    case kMatrixOperation:
74
0
        m_channels.resize( 16 );
75
0
        break;
76
0
    }
77
78
0
    setHint( iHint );
79
0
}
80
81
//-*****************************************************************************
82
XformOp::XformOp( const Alembic::Util::uint8_t iEncodedOp )
83
0
{
84
85
0
    m_type = (XformOperationType)(iEncodedOp >> 4);
86
0
    setHint( iEncodedOp & 0xF );
87
88
0
    switch ( m_type )
89
0
    {
90
0
    case kRotateXOperation:
91
0
    case kRotateYOperation:
92
0
    case kRotateZOperation:
93
0
        m_channels.resize( 1 );
94
0
        break;
95
0
    case kScaleOperation:
96
0
    case kTranslateOperation:
97
0
        m_channels.resize( 3 );
98
0
        break;
99
0
    case kRotateOperation:
100
0
        m_channels.resize( 4 );
101
0
        break;
102
0
    case kMatrixOperation:
103
0
        m_channels.resize( 16 );
104
0
        break;
105
0
    }
106
0
}
107
108
//-*****************************************************************************
109
XformOperationType XformOp::getType() const
110
0
{
111
0
    return m_type;
112
0
}
113
114
//-*****************************************************************************
115
void XformOp::setType( const XformOperationType iType )
116
0
{
117
0
    m_type = iType;
118
0
    m_hint = 0;
119
120
0
    switch ( m_type )
121
0
    {
122
0
    case kRotateXOperation:
123
0
    case kRotateYOperation:
124
0
    case kRotateZOperation:
125
0
        m_channels.resize( 1 );
126
0
        break;
127
0
    case kScaleOperation:
128
0
    case kTranslateOperation:
129
0
        m_channels.resize( 3 );
130
0
        break;
131
0
    case kRotateOperation:
132
0
        m_channels.resize( 4 );
133
0
        break;
134
0
    case kMatrixOperation:
135
0
        m_channels.resize( 16 );
136
0
        break;
137
0
    }
138
0
}
139
140
//-*****************************************************************************
141
uint8_t XformOp::getHint() const
142
0
{
143
0
    return m_hint;
144
0
}
145
146
//-*****************************************************************************
147
void XformOp::setHint( const Alembic::Util::uint8_t iHint )
148
0
{
149
    // if a non-existant hint value is set, default it to 0
150
0
    if ( m_type == kScaleOperation && iHint > kScaleHint )
151
0
    {
152
0
        m_hint = 0;
153
0
    }
154
0
    else if ( m_type == kTranslateOperation && iHint >
155
0
        kRotatePivotTranslationHint )
156
0
    {
157
0
        m_hint = 0;
158
0
    }
159
0
    else if ( ( m_type == kRotateOperation || m_type == kRotateXOperation ||
160
0
        m_type == kRotateYOperation || m_type == kRotateZOperation )
161
0
         && iHint > kRotateOrientationHint )
162
0
    {
163
0
        m_hint = 0;
164
0
    }
165
0
    else if ( m_type == kMatrixOperation && iHint > kMayaShearHint )
166
0
    {
167
0
        m_hint = 0;
168
0
    }
169
0
    else
170
0
    {
171
0
        m_hint = iHint;
172
0
    }
173
0
}
174
175
//-*****************************************************************************
176
bool XformOp::isXAnimated() const
177
0
{
178
0
    if ( m_type == kRotateXOperation || m_type == kRotateYOperation ||
179
0
         m_type == kRotateZOperation )
180
0
    {
181
0
        return false;
182
0
    }
183
184
0
    return m_animChannels.count( 0 ) > 0;
185
0
}
186
187
//-*****************************************************************************
188
bool XformOp::isYAnimated() const
189
0
{
190
0
    if ( m_type == kRotateXOperation || m_type == kRotateYOperation ||
191
0
         m_type == kRotateZOperation )
192
0
    {
193
0
        return false;
194
0
    }
195
196
0
    return m_animChannels.count( 1 ) > 0;
197
0
}
198
199
//-*****************************************************************************
200
bool XformOp::isZAnimated() const
201
0
{
202
0
    if ( m_type == kRotateXOperation || m_type == kRotateYOperation ||
203
0
         m_type == kRotateZOperation )
204
0
    {
205
0
        return false;
206
0
    }
207
208
0
    return m_animChannels.count( 2 ) > 0;
209
0
}
210
211
//-*****************************************************************************
212
bool XformOp::isAngleAnimated() const
213
0
{
214
0
    if ( m_type == kRotateXOperation || m_type == kRotateYOperation ||
215
0
         m_type == kRotateZOperation )
216
0
    {
217
0
        return m_animChannels.count( 0 ) > 0;
218
0
    }
219
220
0
    return m_animChannels.count( 3 ) > 0;
221
0
}
222
223
//-*****************************************************************************
224
bool XformOp::isChannelAnimated( std::size_t iIndex ) const
225
0
{
226
0
    return m_animChannels.count( iIndex ) > 0;
227
0
}
228
229
//-*****************************************************************************
230
std::size_t XformOp::getNumChannels() const
231
0
{
232
0
    return m_channels.size();
233
0
}
234
235
//-*****************************************************************************
236
double XformOp::getDefaultChannelValue( std::size_t iIndex ) const
237
0
{
238
0
    switch ( m_type )
239
0
    {
240
0
    case kTranslateOperation:
241
0
    case kRotateOperation:
242
0
    case kRotateXOperation:
243
0
    case kRotateYOperation:
244
0
    case kRotateZOperation:
245
0
        return 0.0;
246
0
    case kScaleOperation:
247
0
        return 1.0;
248
0
    case kMatrixOperation:
249
0
        switch ( iIndex )
250
0
        {
251
0
        case 0:
252
0
        case 5:
253
0
        case 10:
254
0
        case 15:
255
0
            return 1.0;
256
0
        default:
257
0
            return 0.0;
258
0
        }
259
0
    default:
260
0
        return 0.0;
261
0
    }
262
0
}
263
264
//-*****************************************************************************
265
double XformOp::getChannelValue( std::size_t iIndex ) const
266
0
{
267
0
    return m_channels[iIndex];
268
0
}
269
270
//-*****************************************************************************
271
void XformOp::setChannelValue( std::size_t iIndex, double iVal )
272
0
{
273
0
    m_channels[iIndex] = iVal;
274
0
}
275
276
//-*****************************************************************************
277
Alembic::Util::uint8_t XformOp::getOpEncoding() const
278
0
{
279
0
    return ( m_type << 4 ) | ( m_hint & 0xF );
280
0
}
281
282
//-*****************************************************************************
283
bool XformOp::isTranslateOp() const
284
0
{
285
0
    return m_type == kTranslateOperation;
286
0
}
287
288
//-*****************************************************************************
289
bool XformOp::isScaleOp() const
290
0
{
291
0
    return m_type == kScaleOperation;
292
0
}
293
294
//-*****************************************************************************
295
bool XformOp::isRotateOp() const
296
0
{
297
0
    return m_type == kRotateOperation;
298
0
}
299
300
//-*****************************************************************************
301
bool XformOp::isMatrixOp() const
302
0
{
303
0
    return m_type == kMatrixOperation;
304
0
}
305
306
//-*****************************************************************************
307
bool XformOp::isRotateXOp() const
308
0
{
309
0
    return m_type == kRotateXOperation;
310
0
}
311
312
//-*****************************************************************************
313
bool XformOp::isRotateYOp() const
314
0
{
315
0
    return m_type == kRotateYOperation;
316
0
}
317
318
//-*****************************************************************************
319
bool XformOp::isRotateZOp() const
320
0
{
321
0
    return m_type == kRotateZOperation;
322
0
}
323
324
//-*****************************************************************************
325
void XformOp::setVector( const Abc::V3d &iVec )
326
0
{
327
0
    ABCA_ASSERT( m_type != kMatrixOperation,
328
0
                 "Meaningless to set Abc::V3d on matrix op" );
329
330
0
    m_channels[0] = iVec.x;
331
0
    m_channels[1] = iVec.y;
332
0
    m_channels[2] = iVec.z;
333
0
}
334
335
//-*****************************************************************************
336
void XformOp::setTranslate( const Abc::V3d &iTrans )
337
0
{
338
0
    ABCA_ASSERT( m_type == kTranslateOperation,
339
0
                 "Meaningless to set translate on non-translate op." );
340
341
0
    this->setVector( iTrans );
342
0
}
343
344
//-*****************************************************************************
345
void XformOp::setScale( const Abc::V3d &iScale )
346
0
{
347
0
    ABCA_ASSERT( m_type == kScaleOperation,
348
0
                 "Meaningless to set scale on non-scale op." );
349
350
0
    this->setVector( iScale );
351
0
}
352
353
//-*****************************************************************************
354
void XformOp::setAxis( const Abc::V3d &iAxis )
355
0
{
356
0
    ABCA_ASSERT( m_type == kRotateOperation,
357
0
                 "Meaningless to set rotation axis on non-rotation or fixed "
358
0
                 "angle rotation op." );
359
360
0
    this->setVector( iAxis );
361
0
}
362
363
//-*****************************************************************************
364
void XformOp::setAngle( const double iAngle )
365
0
{
366
0
    switch ( m_type )
367
0
    {
368
0
    case kRotateOperation:
369
0
        m_channels[3] = iAngle;
370
0
        break;
371
0
    case kRotateXOperation:
372
0
    case kRotateYOperation:
373
0
    case kRotateZOperation:
374
0
        m_channels[0] = iAngle;
375
0
        break;
376
0
    default:
377
0
        ABCA_THROW( "Meaningless to set rotation angle on non-rotation op." );
378
0
    }
379
0
}
380
381
//-*****************************************************************************
382
void XformOp::setMatrix( const Abc::M44d &iMatrix )
383
0
{
384
0
    ABCA_ASSERT( m_type == kMatrixOperation,
385
0
                 "Cannot set non-matrix op from Abc::M44d" );
386
387
0
    for ( size_t i = 0 ; i < 4 ; ++i )
388
0
    {
389
0
        for ( size_t j = 0 ; j < 4 ; ++j )
390
0
        {
391
0
            m_channels[( i * 4 ) + j] = iMatrix.x[i][j];
392
0
        }
393
0
    }
394
0
}
395
396
//-*****************************************************************************
397
Abc::V3d XformOp::getVector() const
398
0
{
399
0
    ABCA_ASSERT( m_type != kMatrixOperation,
400
0
                 "Meaningless to get Abc::V3d from matrix op" );
401
402
0
    return Abc::V3d( m_channels[0], m_channels[1], m_channels[2] );
403
0
}
404
405
//-*****************************************************************************
406
Abc::V3d XformOp::getTranslate() const
407
0
{
408
0
    ABCA_ASSERT( m_type == kTranslateOperation,
409
0
                 "Meaningless to get translate vector from non-translate op." );
410
411
0
    return this->getVector();
412
0
}
413
414
//-*****************************************************************************
415
Abc::V3d XformOp::getScale() const
416
0
{
417
0
    ABCA_ASSERT( m_type == kScaleOperation,
418
0
                 "Meaningless to get scaling vector from non-scale op." );
419
420
0
    return this->getVector();
421
0
}
422
423
//-*****************************************************************************
424
Abc::V3d XformOp::getAxis() const
425
0
{
426
0
    switch ( m_type )
427
0
    {
428
0
    case kRotateOperation:
429
0
        return this->getVector();
430
0
    case kRotateXOperation:
431
0
        return Abc::V3d(1.0, 0.0, 0.0);
432
0
    case kRotateYOperation:
433
0
        return Abc::V3d(0.0, 1.0, 0.0);
434
0
    case kRotateZOperation:
435
0
        return Abc::V3d(0.0, 0.0, 1.0);
436
0
    default:
437
0
        ABCA_THROW( "Meaningless to get rotation axis from non-rotation op." );
438
0
    }
439
440
0
    return Abc::V3d(0.0, 0.0, 0.0);
441
0
}
442
443
//-*****************************************************************************
444
double XformOp::getAngle() const
445
0
{
446
0
    switch ( m_type )
447
0
    {
448
0
    case kRotateOperation:
449
0
        return m_channels[3];
450
0
    case kRotateXOperation:
451
0
    case kRotateYOperation:
452
0
    case kRotateZOperation:
453
0
        return m_channels[0];
454
0
    default:
455
0
        ABCA_THROW( "Meaningless to get rotation angle from non-rotation op." );
456
0
    }
457
458
0
    return 0.0;
459
0
}
460
461
//-*****************************************************************************
462
double XformOp::getXRotation() const
463
0
{
464
0
    ABCA_ASSERT( m_type == kRotateOperation || m_type == kRotateXOperation,
465
0
                 "Meaningless to get rotation angle from non-rotation op." );
466
467
0
    if ( m_type == kRotateXOperation )
468
0
    {
469
0
        return m_channels[0];
470
0
    }
471
0
    else
472
0
    {
473
0
        Abc::M44d m;
474
0
        Abc::V3d rot;
475
0
        m.makeIdentity();
476
0
        m.setAxisAngle( this->getVector(), DegreesToRadians( m_channels[3] ) );
477
0
        Imath::extractEulerXYZ( m, rot );
478
0
        return RadiansToDegrees( rot[0] );
479
0
    }
480
0
}
481
482
//-*****************************************************************************
483
double XformOp::getYRotation() const
484
0
{
485
0
    ABCA_ASSERT( m_type == kRotateOperation || m_type == kRotateYOperation,
486
0
                 "Meaningless to get rotation angle from non-rotation op." );
487
488
0
    if ( m_type == kRotateYOperation )
489
0
    {
490
0
        return m_channels[0];
491
0
    }
492
0
    else
493
0
    {
494
0
        Abc::M44d m;
495
0
        Abc::V3d rot;
496
0
        m.makeIdentity();
497
0
        m.setAxisAngle( this->getVector(), DegreesToRadians( m_channels[3] ) );
498
0
        Imath::extractEulerXYZ( m, rot );
499
0
        return RadiansToDegrees( rot[1] );
500
0
    }
501
0
}
502
503
//-*****************************************************************************
504
double XformOp::getZRotation() const
505
0
{
506
0
    ABCA_ASSERT( m_type == kRotateOperation || m_type == kRotateZOperation,
507
0
                 "Meaningless to get rotation angle from non-rotation op." );
508
509
0
    if ( m_type == kRotateZOperation )
510
0
    {
511
0
        return m_channels[0];
512
0
    }
513
0
    else
514
0
    {
515
0
        Abc::M44d m;
516
0
        Abc::V3d rot;
517
0
        m.makeIdentity();
518
0
        m.setAxisAngle( this->getVector(), DegreesToRadians( m_channels[3] ) );
519
0
        Imath::extractEulerXYZ( m, rot );
520
0
        return RadiansToDegrees( rot[2] );
521
0
    }
522
0
}
523
524
//-*****************************************************************************
525
Abc::M44d XformOp::getMatrix() const
526
0
{
527
0
    ABCA_ASSERT( m_type == kMatrixOperation,
528
0
                 "Can't get matrix from non-matrix op." );
529
530
0
    Abc::M44d ret;
531
532
0
    for ( size_t i = 0 ; i < 4 ; ++i )
533
0
    {
534
0
        for ( size_t j = 0 ; j < 4 ; ++j )
535
0
        {
536
0
            ret.x[i][j] = m_channels[( i * 4 ) + j];
537
0
        }
538
0
    }
539
540
0
    return ret;
541
0
}
542
543
} // End namespace ALEMBIC_VERSION_NS
544
} // End namespace AbcGeom
545
} // End namespace Alembic