ACF $AcfVersion:0$
TFulcrumGrid.h
Go to the documentation of this file.
1// SPDX-License-Identifier: LGPL-2.1-or-later OR GPL-2.0-or-later OR GPL-3.0-or-later OR LicenseRef-ACF-Commercial
2#pragma once
3
4
5// Qt includes
6#include <QtCore/QObject>
7#include <QtCore/QtAlgorithms>
8#include <QtCore/QVector>
9
10// ACF includes
12#include <iser/ISerializable.h>
13#include <iser/CArchiveTag.h>
14
15
16namespace imath
17{
18
19
32template <class Position, class Fulcrums>
33class TFulcrumGrid: virtual public iser::ISerializable
34{
35public:
36 typedef typename Fulcrums::ElementType FulcrumType;
37 typedef typename Fulcrums::IndexType FulcrumIndex;
38 typedef typename Fulcrums::SizesType FulcrumSizes;
39 typedef Position PositionType;
40
45 {
46 CF_SORT_LAYERS = 0x8352707
47 };
48
50
54 void Reset();
55
60
64 int GetDimensionsCount() const;
65
71 virtual bool SetDimensionsCount(int count);
72
76 int GetLayersCount(int dimension) const;
77
82 virtual void SetLayersCount(int dimension, int count);
83
87 double GetLayerPosition(int dimension, int layerIndex) const;
88
94 virtual void SetLayerPosition(int dimension, int layerIndex, double position);
95
99 void GetFulcrumPosition(const FulcrumIndex& index, PositionType& result) const;
100
104 const FulcrumType& GetFulcrumAtIndex(const FulcrumIndex& index) const;
105
109 virtual void SetFulcrumAtIndex(const FulcrumIndex& index, const FulcrumType& value);
110
115 int InsertLayer(int dimension, double position);
116
120 virtual void RemoveLayer(int dimension, int layerIndex);
121
122 // reimplemented (iser::ISerializable)
123 virtual bool Serialize(iser::IArchive& archive) override;
124
125 // operators
128
129protected:
133 virtual void SortFulcrums();
134
142 int FindLayerIndex(int dimension, double value) const;
146 typename Fulcrums::IndexType FindIndices(const PositionType& argument) const;
147
148protected:
150
151private:
152 Fulcrums m_fulcrums;
153
154 typedef QVector<double> LayerPositions;
155 typedef QVector<LayerPositions> Layers;
156
157 Layers m_layers;
158};
159
160
161
162// inline methods
163
164template <class Position, class Fulcrums>
167{
168 return m_fulcrums.GetSizes();
169}
170
171
172template <class Position, class Fulcrums>
174{
175 return m_fulcrums.GetDimensionsCount();
176}
177
178
179template <class Position, class Fulcrums>
181{
182 Q_ASSERT(dimension >= 0);
183 Q_ASSERT(dimension < int(m_layers.size()));
184
185 return m_layers[dimension].size();
186}
187
188
189template <class Position, class Fulcrums>
190inline double TFulcrumGrid<Position, Fulcrums>::GetLayerPosition(int dimension, int layerIndex) const
191{
192 Q_ASSERT(dimension >= 0);
193 Q_ASSERT(dimension < int(m_layers.size()));
194
195 const LayerPositions& positions = m_layers[dimension];
196
197 Q_ASSERT(layerIndex >= 0);
198 Q_ASSERT(layerIndex < int(positions.size()));
199
200 return positions[layerIndex];
201}
202
203
204// public methods
205
206template <class Position, class Fulcrums>
208{
209 m_layers.resize(m_fulcrums.GetDimensionsCount());
210}
211
212
213template <class Position, class Fulcrums>
215{
216 m_fulcrums.Reset();
217
218 for (Layers::iterator iter = m_layers.begin(); iter != m_layers.end(); ++iter){
219 iter->clear();
220 }
221
222 m_layers.resize(m_fulcrums.GetDimensionsCount());
223}
224
225
226template <class Position, class Fulcrums>
228{
229 if (m_fulcrums.SetDimensionsCount(count)){
230 m_layers.resize(count);
231
232 return true;
233 }
234
235 return false;
236}
237
238
239template <class Position, class Fulcrums>
241{
242 Q_ASSERT(dimension >= 0);
243 Q_ASSERT(dimension < int(m_layers.size()));
244
245 m_layers[dimension].resize(count);
246 m_fulcrums.SetSize(dimension, count);
247}
248
249
250template <class Position, class Fulcrums>
251void TFulcrumGrid<Position, Fulcrums>::SetLayerPosition(int dimension, int layerIndex, double position)
252{
253 Q_ASSERT(dimension >= 0);
254 Q_ASSERT(dimension < int(m_layers.size()));
255
256 LayerPositions& positions = m_layers[dimension];
257
258 Q_ASSERT(layerIndex >= 0);
259 Q_ASSERT(layerIndex < int(positions.size()));
260
261 istd::CChangeNotifier notifier(this, &s_fulcrumPositionChange);
262 Q_UNUSED(notifier);
263
264 positions[layerIndex] = position;
265}
266
267
268template <class Position, class Fulcrums>
270{
271 int layersCount = int(m_layers.size());
272 Q_ASSERT(layersCount <= index.GetDimensionsCount());
273
274 result.SetElementsCount(layersCount);
275
276 for (int i = 0; i < layersCount; ++i){
277 const LayerPositions& positions = m_layers[i];
278
279 Q_ASSERT(index[i] >= 0);
280 Q_ASSERT(index[i] < int(positions.size()));
281
282 result[i] = positions[index[i]];
283 }
284}
285
286
287template <class Position, class Fulcrums>
290{
291 return m_fulcrums.GetAt(index);
292}
293
294
295template <class Position, class Fulcrums>
297{
298 istd::CChangeNotifier notifier(this);
299
300 m_fulcrums.SetAt(index, value);
301}
302
303
304template <class Position, class Fulcrums>
305int TFulcrumGrid<Position, Fulcrums>::InsertLayer(int dimension, double position)
306{
307 Q_ASSERT(dimension >= 0);
308 Q_ASSERT(dimension < m_fulcrums.GetDimensionsCount());
309
310 Fulcrums newFulcrums = m_fulcrums;
311
312 newFulcrums.SetSize(dimension, m_fulcrums.GetSize(dimension) + 1);
313
314 int layerIndex = FindLayerIndex(dimension, position);
315
316 LayerPositions& positions = m_layers[dimension];
317
318 double prevPosition = position;
319 double nextPosition = position;
320 if (!positions.isEmpty()){
321 if (layerIndex >= 0){
322 prevPosition = positions[layerIndex];
323 }
324 if (layerIndex < GetLayersCount(dimension) - 1){
325 nextPosition = positions[layerIndex + 1];
326 }
327 }
328 Q_ASSERT(position >= prevPosition);
329 Q_ASSERT(position <= nextPosition);
330
331 double prevFactor = 0.5;
332 if (nextPosition - prevPosition > I_BIG_EPSILON){
333 prevFactor = (position - prevPosition) / (nextPosition - prevPosition);
334
335 Q_ASSERT(prevFactor >= 0);
336 Q_ASSERT(prevFactor - I_EPSILON <= 1.0);
337 }
338 double nextFactor = 1 - prevFactor;
339
340 int oldLayersCount = int(positions.size());
341 Q_ASSERT(oldLayersCount == m_fulcrums.GetSize(dimension));
342
343 for ( typename Fulcrums::Iterator destIter = newFulcrums.Begin();
344 destIter != newFulcrums.End();
345 ++destIter){
346 PositionType sourceIndex = destIter;
347 if ((destIter[dimension] >= layerIndex) && (sourceIndex[dimension] > 0)){
348 sourceIndex[dimension]--;
349
350 if ((destIter[dimension] == layerIndex) && (layerIndex < oldLayersCount)){
351 PositionType prevFulcrumPosition;
352 GetFulcrumPosition(sourceIndex, prevFulcrumPosition);
353
354 PositionType nextFulcrumPosition;
355 GetFulcrumPosition(destIter, nextFulcrumPosition);
356
357 PositionType position = prevFactor * prevFulcrumPosition + nextFactor * nextFulcrumPosition;
358
359 newFulcrums[destIter] = GetValueAt(position);
360
361 continue;
362 }
363 }
364
365 *destIter = m_fulcrums[sourceIndex];
366 }
367
368 positions.insert(positions.begin() + layerIndex + 1, position);
369 m_fulcrums = newFulcrums;
370
371 return layerIndex;
372}
373
374
375template <class Position, class Fulcrums>
376void TFulcrumGrid<Position, Fulcrums>::RemoveLayer(int dimension, int layerIndex)
377{
378 Q_ASSERT(dimension >= 0);
379 Q_ASSERT(dimension < GetDimensionsCount());
380 Q_ASSERT(m_fulcrums.GetSize(dimension) > 0);
381
382 Fulcrums newFulcrums = m_fulcrums;
383
384 newFulcrums.SetSize(dimension, m_fulcrums.GetSize(dimension) + 1);
385
386 LayerPositions& positions = m_layers[dimension];
387
388 for ( typename Fulcrums::Iterator destIter = newFulcrums.Begin();
389 destIter != newFulcrums.End();
390 ++destIter){
391 FulcrumIndex sourceIndex = destIter;
392 if (destIter[dimension] >= layerIndex){
393 sourceIndex.IncreaseAt(dimension);
394 }
395
396 *destIter = m_fulcrums[sourceIndex];
397 }
398
399 positions.erase(positions.begin() + layerIndex);
400 m_fulcrums = newFulcrums;
401}
402
403
404// reimplemented (iser::ISerializable)
405
406template <class Position, class Fulcrums>
408{
409 bool retVal = true;
410
411 iser::CArchiveTag gridTag("Grid", "Description of fulcrums grid", iser::CArchiveTag::TT_MULTIPLE);
412 iser::CArchiveTag positionsTag("Positions", "List of positions at single axis of fulcrum grid", iser::CArchiveTag::TT_MULTIPLE, &gridTag);
413 iser::CArchiveTag positionTag("Position", "Single layer position", iser::CArchiveTag::TT_LEAF, &positionsTag);
414 iser::CArchiveTag fulcrumsTag("Fulcrums", "List of fulcrums", iser::CArchiveTag::TT_GROUP);
415 iser::CArchiveTag fulcrumTag("Fulcrum", "Single fulcrum", iser::CArchiveTag::TT_GROUP, &fulcrumsTag);
416
417 bool isStoring = archive.IsStoring();
418
419 istd::CChangeNotifier notifier(isStoring? NULL: this);
420
421 int dimensionsCount = m_fulcrums.GetDimensionsCount();
422 Q_ASSERT(dimensionsCount == int(m_layers.size()));
423
424 retVal = retVal && archive.BeginMultiTag(gridTag, positionsTag, dimensionsCount);
425
426 if (!isStoring && (dimensionsCount != m_fulcrums.GetDimensionsCount())){
427 if (!SetDimensionsCount(dimensionsCount)){
428 return false;
429 }
430 }
431
432 FulcrumSizes sizes = m_fulcrums.GetSizes();
433 Q_ASSERT(sizes.GetDimensionsCount() >= dimensionsCount);
434
435 for (int dimensionIndex = 0; dimensionIndex < dimensionsCount; ++dimensionIndex){
436 LayerPositions& positions = m_layers[dimensionIndex];
437
438 int& positionsCount = sizes[dimensionIndex];
439 Q_ASSERT(positionsCount == int(positions.size()));
440
441 retVal = retVal && archive.BeginMultiTag(positionsTag, positionTag, positionsCount);
442
443 if (!isStoring){
444 if (!retVal){
445 Reset();
446
447 return false;
448 }
449
450 SetLayersCount(dimensionIndex, positionsCount);
451 }
452
453 for (int positionIndex = 0; positionIndex < positionsCount; ++positionIndex){
454 retVal = retVal && archive.BeginTag(positionTag);
455 retVal = retVal && archive.Process(positions[positionIndex]);
456 retVal = retVal && archive.EndTag(positionTag);
457 }
458
459 retVal = retVal && archive.EndTag(positionsTag);
460 }
461
462 retVal = retVal && archive.EndTag(gridTag);
463
464 retVal = retVal && archive.BeginTag(fulcrumsTag);
465
466 for ( typename Fulcrums::Iterator iter = m_fulcrums.Begin();
467 iter != m_fulcrums.End();
468 ++iter){
469 FulcrumType& point = *iter;
470
471 retVal = retVal && archive.BeginTag(fulcrumTag);
472 retVal = retVal && point.Serialize(archive);
473 retVal = retVal && archive.EndTag(fulcrumTag);
474 }
475
476 retVal = retVal && archive.EndTag(fulcrumsTag);
477
478 return retVal;
479}
480
481
482// operators
483
484template <class Position, class Fulcrums>
486{
487 return (m_fulcrums == value.m_fulcrums) && (m_layers == value.m_layers);
488}
489
490
491template <class Position, class Fulcrums>
493{
494 return (m_fulcrums != value.m_fulcrums) || (m_layers != value.m_layers);
495}
496
497
498// protected methods
499
500template <class Position, class Fulcrums>
502{
503 for (Layers::iterator iter = m_layers.begin(); iter != m_layers.end(); ++iter){
504 LayerPositions& positions = *iter;
505
506 qSort(positions.begin(), positions.end());
507 }
508}
509
510
511template <class Position, class Fulcrums>
512int TFulcrumGrid<Position, Fulcrums>::FindLayerIndex(int dimension, double value) const
513{
514 Q_ASSERT(dimension >= 0);
515 Q_ASSERT(dimension < GetDimensionsCount());
516
517 const LayerPositions& positions = m_layers[dimension];
518
519 int left = 0;
520 int right = int(positions.size());
521
522 while (left != right){
523 int center = (left + right) / 2;
524
525 if (value >= positions[center]){
526 left = center + 1;
527 }
528 else{
529 right = center;
530 }
531 }
532
533 return left - 1;
534}
535
536
537template <class Position, class Fulcrums>
538typename Fulcrums::IndexType
540{
541 int dimensionsCount = GetDimensionsCount();
542
543 FulcrumIndex retVal(dimensionsCount);
544
545 for (int i = 0; i < dimensionsCount; ++i){
546 retVal[i] = FindLayerIndex(i, argument[i]);
547 }
548
549 return retVal;
550}
551
552
553// protected static members
554
555template <class Position, class Fulcrums>
556const istd::IChangeable::ChangeSet TFulcrumGrid<Position, Fulcrums>::s_fulcrumPositionChange(CF_SORT_LAYERS, QObject::tr("Change fulcrum position"));
557
558
559} // namespace imath
560
561
Representation of fulcrums in multi-dimesional regular grid.
virtual bool SetDimensionsCount(int count)
Set number of dimensions.
void Reset()
Removes all fulcrum points.
virtual void SetFulcrumAtIndex(const FulcrumIndex &index, const FulcrumType &value)
Set single fulcrum point.
virtual void SetLayerPosition(int dimension, int layerIndex, double position)
Set position of specified layer of fulcrums.
int InsertLayer(int dimension, double position)
Inserts single fulcrum layer.
virtual bool Serialize(iser::IArchive &archive) override
Load or store state of this object as a archive stream.
const FulcrumType & GetFulcrumAtIndex(const FulcrumIndex &index) const
Get value at specified index.
double GetLayerPosition(int dimension, int layerIndex) const
Get position of specified layer of fulcrums.
Fulcrums::IndexType FindIndices(const PositionType &argument) const
Find indices of cuboid containing specified argument value.
FulcrumSizes GetGridSize() const
Return complete grid size.
int GetDimensionsCount() const
Get number of dimensions.
Fulcrums::IndexType FulcrumIndex
Fulcrums::SizesType FulcrumSizes
static const ChangeSet s_fulcrumPositionChange
virtual void SetLayersCount(int dimension, int count)
Set number of fulcrum layers at specified dimension.
ChangeFlags
Data model change notification flags.
virtual void SortFulcrums()
Sort fulcrums in this collection.
bool operator!=(const TFulcrumGrid< Position, Fulcrums > &value) const
int GetLayersCount(int dimension) const
Get number of fulcrum points used in this function.
bool operator==(const TFulcrumGrid< Position, Fulcrums > &value) const
Fulcrums::ElementType FulcrumType
int FindLayerIndex(int dimension, double value) const
Find layer index of specified value for specified dimension.
virtual void RemoveLayer(int dimension, int layerIndex)
Remove fulcrums at spacified layer.
void GetFulcrumPosition(const FulcrumIndex &index, PositionType &result) const
Get position of node at specified grid index.
Process tag used to group data in archive stream.
Definition CArchiveTag.h:22
@ TT_GROUP
Normal tag used for grouping of tags or processed elements.
Definition CArchiveTag.h:37
@ TT_LEAF
Leaf tag, it can contain only one primitive element.
Definition CArchiveTag.h:48
@ TT_MULTIPLE
Multiple tag containing variable number of child tags.
Definition CArchiveTag.h:42
Represents an input/output persistence archive for object serialization.
Definition IArchive.h:164
virtual bool Process(bool &value)=0
Processes (reads or writes) a boolean value.
virtual bool EndTag(const CArchiveTag &tag)=0
Ends a tagged section in the archive.
virtual bool BeginMultiTag(const CArchiveTag &tag, const CArchiveTag &subTag, int &count)=0
Begins a tagged section containing multiple elements of the same type.
virtual bool IsStoring() const =0
Checks if this archive is in storing (writing) or loading (reading) mode.
virtual bool BeginTag(const CArchiveTag &tag)=0
Begins a tagged section in the archive.
Common class for all classes which objects can be archived or restored from archive.
Help class which provides the automatic update mechanism of the model.
Set of change flags (its IDs).
Definition IChangeable.h:36
#define NULL
Definition istd.h:74
#define I_EPSILON
Some very small number.
Definition istd.h:31
static const double I_BIG_EPSILON
Definition istd.h:26
Package with mathematical functions and algebraical primitives.