@@ -59,6 +59,119 @@ QStringList parseCSVLine(const QString &srcLine, char delimiter)
5959 return line.split (delimiter);
6060}
6161
62+ std::optional<int > toInteger (const QString &text)
63+ {
64+ bool ok = true ;
65+ const auto value = text.toInt (&ok);
66+ if (ok)
67+ return value;
68+ return {};
69+ }
70+
71+ std::optional<Color> toColorWithClipping (const QString &textR,
72+ const QString &textG,
73+ const QString &textB,
74+ const QString &textA)
75+ {
76+ bool ok = true ;
77+
78+ const auto r = toInteger (textR);
79+ const auto g = toInteger (textG);
80+ const auto b = toInteger (textB);
81+ const auto a = toInteger (textA);
82+
83+ if (r && g && b && a)
84+ return Color (functions::clip (*r, 0 , 255 ),
85+ functions::clip (*g, 0 , 255 ),
86+ functions::clip (*b, 0 , 255 ),
87+ functions::clip (*a, 0 , 255 ));
88+ return {};
89+ }
90+
91+ enum class SpecifiedType
92+ {
93+ map,
94+ range,
95+ vector,
96+ line
97+ };
98+
99+ struct ParsedType
100+ {
101+ int typeID{};
102+ std::string typeName{};
103+ std::optional<SpecifiedType> specifiedType{};
104+
105+ std::optional<StatisticsType::ValueDataOptions> valueDataOptions;
106+ std::optional<StatisticsType::VectorDataOptions> vectorDataOptions;
107+ StatisticsType::GridOptions gridOptions;
108+ };
109+
110+ void checkAndAddTypeToStatisticsData (StatisticsData &statisticsData,
111+ const std::optional<ParsedType> &type)
112+ {
113+ if (!type)
114+ return ;
115+
116+ const bool hasNoValueOrDataOptions = (!type->valueDataOptions && !type->vectorDataOptions );
117+ if (hasNoValueOrDataOptions)
118+ return ;
119+
120+ statisticsData.addStatType (StatisticsTypeBuilder (type->typeID , type->typeName )
121+ .withOptionalValueDataOptions (type->valueDataOptions )
122+ .withOptionalVectorDataOptions (type->vectorDataOptions )
123+ .withGridOptions (type->gridOptions )
124+ .build ());
125+ }
126+
127+ std::optional<ParsedType> parseHeaderLine (const QStringList &lineItems)
128+ {
129+ if (lineItems.count () < 5 )
130+ return {};
131+
132+ ParsedType newType;
133+
134+ if (const auto typeID = toInteger (lineItems[2 ]))
135+ newType.typeID = *typeID;
136+ else
137+ return {};
138+
139+ newType.typeName = lineItems[3 ].toStdString ();
140+
141+ const auto typeEntry = lineItems[4 ];
142+ if (typeEntry == " map" )
143+ newType.specifiedType = SpecifiedType::map;
144+ else if (typeEntry == " range" )
145+ newType.specifiedType = SpecifiedType::range;
146+ else if (typeEntry == " vector" )
147+ newType.specifiedType = SpecifiedType::vector;
148+ else if (typeEntry == " line" )
149+ newType.specifiedType = SpecifiedType::line;
150+ else
151+ return {};
152+
153+ return newType;
154+ }
155+
156+ std::optional<color::ColorMapper> parseColorMapperFromRange (const QStringList &lineItems)
157+ {
158+ if (lineItems.count () < 12 )
159+ return {};
160+
161+ const auto minValue = toInteger (lineItems[2 ]);
162+ const auto minColor =
163+ toColorWithClipping (lineItems[4 ], lineItems[6 ], lineItems[8 ], lineItems[10 ]);
164+
165+ const auto maxValue = toInteger (lineItems[3 ]);
166+ const auto maxColor =
167+ toColorWithClipping (lineItems[5 ], lineItems[7 ], lineItems[9 ], lineItems[11 ]);
168+
169+ if (!minValue || !minColor || !maxValue || !maxColor)
170+ return {};
171+
172+ return color::ColorMapper ({*minValue, *maxValue}, *minColor, *maxColor);
173+ }
174+
62175} // namespace
63176
64177StatisticsFileCSV::StatisticsFileCSV (const std::string &filename, StatisticsData &statisticsData)
@@ -94,7 +207,6 @@ void StatisticsFileCSV::readFrameAndTypePositionsFromFile(std::atomic_bool &brea
94207 uint64_t lineBufferStartPos = 0 ;
95208 int lastPOC = INT_INVALID;
96209 int lastType = INT_INVALID;
97- bool sortingFixed = false ;
98210
99211 this ->parsingInfo .parsingProgress = 0.0 ;
100212
@@ -148,14 +260,8 @@ void StatisticsFileCSV::readFrameAndTypePositionsFromFile(std::atomic_bool &brea
148260 // we found a new type but the POC stayed the same.
149261 // This seems to be an interleaved file
150262 // Check if we already collected a start position for this type
151- if (!sortingFixed)
152- {
153- // we only check the first occurence of this, in a non-interleaved file
154- // the above condition can be met and will reset fileSortedByPOC
155-
263+ if (this ->parsingInfo .fileSorting == FileSorting::Unknown)
156264 this ->parsingInfo .fileSorting = FileSorting::SortedByPOC;
157- sortingFixed = true ;
158- }
159265 lastType = typeID;
160266 if (this ->pocTypeFileposMap [poc].count (typeID) == 0 )
161267 {
@@ -166,8 +272,8 @@ void StatisticsFileCSV::readFrameAndTypePositionsFromFile(std::atomic_bool &brea
166272 else if (poc != lastPOC)
167273 {
168274 // this is apparently not sorted by POCs and we will not check it further
169- if (!sortingFixed )
170- sortingFixed = true ;
275+ if (this -> parsingInfo . fileSorting == FileSorting::Unknown )
276+ this -> parsingInfo . fileSorting = FileSorting::SortedByType ;
171277
172278 // We found a new POC
173279 if (this ->parsingInfo .fileSorting == FileSorting::SortedByPOC)
@@ -346,21 +452,10 @@ void StatisticsFileCSV::readHeaderFromFile(StatisticsData &statisticsData)
346452 return ;
347453
348454 statisticsData.clear ();
349-
350- struct ParsedData
351- {
352- int typeID{};
353- std::string typeName{};
354-
355- std::optional<StatisticsType::ValueDataOptions> valueDataOptions;
356- std::optional<StatisticsType::VectorDataOptions> vectorDataOptions;
357- StatisticsType::GridOptions gridOptions;
358- };
359- std::optional<ParsedData> type;
455+ std::optional<ParsedType> currentType;
360456
361457 while (!this ->file .atEnd ())
362458 {
363- // read one line
364459 auto aLineByteArray = this ->file .readLine ();
365460 QString aLine (aLineByteArray);
366461
@@ -370,44 +465,19 @@ void StatisticsFileCSV::readHeaderFromFile(StatisticsData &statisticsData)
370465 if (rowItemList[0 ].isEmpty ())
371466 continue ;
372467
373- // either a new type or a line which is not header finishes the last type
374- if (((rowItemList[ 1 ] == " type " ) || (rowItemList[ 0 ][ 0 ] != ' % ' )) && type )
468+ const bool isNonHeaderLine = (rowItemList[ 0 ][ 0 ] != ' % ' );
469+ if (isNonHeaderLine )
375470 {
376- // Last type is complete. Store this initial state.
377- statisticsData.addStatType (StatisticsTypeBuilder (type->typeID , type->typeName )
378- .withOptionalValueDataOptions (type->valueDataOptions )
379- .withOptionalVectorDataOptions (type->vectorDataOptions )
380- .withGridOptions (type->gridOptions )
381- .build ());
382-
383- type.reset ();
384-
385- // if we found a non-header line, stop here
386- if (rowItemList[0 ][0 ] != ' %' )
387- return ;
471+ checkAndAddTypeToStatisticsData (statisticsData, currentType);
472+ return ;
388473 }
389474
390475 if (rowItemList[1 ] == " type" )
391476 {
392- // Start of a new type
393- type.emplace ();
394- type->typeID = rowItemList[2 ].toInt ();
395- type->typeName = rowItemList[3 ].toStdString ();
477+ checkAndAddTypeToStatisticsData (statisticsData, currentType);
478+ currentType.reset ();
396479
397- // The next entry (4) is "map", "range", or "vector"
398- if (rowItemList.count () >= 5 )
399- {
400- if (rowItemList[4 ] == " map" || rowItemList[4 ] == " range" )
401- {
402- type->valueDataOptions = StatisticsType::ValueDataOptions ();
403- }
404- else if (rowItemList[4 ] == " vector" || rowItemList[4 ] == " line" )
405- {
406- type->vectorDataOptions = StatisticsType::VectorDataOptions ();
407- if (rowItemList[4 ] == " line" )
408- type->vectorDataOptions ->arrowHead = ArrowHead::none;
409- }
410- }
480+ currentType = parseHeaderLine (rowItemList);
411481 }
412482 else if (rowItemList[1 ] == " mapColor" )
413483 {
@@ -419,60 +489,53 @@ void StatisticsFileCSV::readHeaderFromFile(StatisticsData &statisticsData)
419489 auto b = (unsigned char )rowItemList[5 ].toInt ();
420490 auto a = (unsigned char )rowItemList[6 ].toInt ();
421491
422- type->valueDataOptions ->colorMapper ->mappingType = color::MappingType::Map;
423- type->valueDataOptions ->colorMapper ->colorMap [id] = Color (r, g, b, a);
492+ if (!currentType->valueDataOptions )
493+ currentType->valueDataOptions .emplace ();
494+ currentType->valueDataOptions ->colorMapper ->mappingType = color::MappingType::Map;
495+ currentType->valueDataOptions ->colorMapper ->colorMap [id] = Color (r, g, b, a);
424496 }
425497 else if (rowItemList[1 ] == " range" )
426498 {
427- // This is a range with min/max
428- auto min = rowItemList[2 ].toInt ();
429- auto r = (unsigned char )rowItemList[4 ].toInt ();
430- auto g = (unsigned char )rowItemList[6 ].toInt ();
431- auto b = (unsigned char )rowItemList[8 ].toInt ();
432- auto a = (unsigned char )rowItemList[10 ].toInt ();
433- auto minColor = Color (r, g, b, a);
434-
435- auto max = rowItemList[3 ].toInt ();
436- r = rowItemList[5 ].toInt ();
437- g = rowItemList[7 ].toInt ();
438- b = rowItemList[9 ].toInt ();
439- a = rowItemList[11 ].toInt ();
440- auto maxColor = Color (r, g, b, a);
441-
442- type->valueDataOptions ->colorMapper = color::ColorMapper ({min, max}, minColor, maxColor);
499+ if (currentType->specifiedType == SpecifiedType::range)
500+ if (const auto colorMapper = parseColorMapperFromRange (rowItemList))
501+ {
502+ if (!currentType->valueDataOptions )
503+ currentType->valueDataOptions .emplace ();
504+ currentType->valueDataOptions ->colorMapper = *colorMapper;
505+ }
443506 }
444507 else if (rowItemList[1 ] == " defaultRange" )
445508 {
446- // This is a color gradient function
447509 int min = rowItemList[2 ].toInt ();
448510 int max = rowItemList[3 ].toInt ();
449511 auto rangeName = rowItemList[4 ].toStdString ();
450512
451- type->valueDataOptions ->colorMapper = color::ColorMapper ({min, max}, rangeName);
513+ currentType->valueDataOptions ->colorMapper ->mappingType = color::MappingType::Predefined;
514+ currentType->valueDataOptions ->colorMapper = color::ColorMapper ({min, max}, rangeName);
452515 }
453516 else if (rowItemList[1 ] == " vectorColor" )
454517 {
455- auto r = (unsigned char )rowItemList[2 ].toInt ();
456- auto g = (unsigned char )rowItemList[3 ].toInt ();
457- auto b = (unsigned char )rowItemList[4 ].toInt ();
458- auto a = (unsigned char )rowItemList[5 ].toInt ();
459- type ->vectorDataOptions ->style ->color = Color (r, g, b, a);
518+ auto r = (unsigned char )rowItemList[2 ].toInt ();
519+ auto g = (unsigned char )rowItemList[3 ].toInt ();
520+ auto b = (unsigned char )rowItemList[4 ].toInt ();
521+ auto a = (unsigned char )rowItemList[5 ].toInt ();
522+ currentType ->vectorDataOptions ->style ->color = Color (r, g, b, a);
460523 }
461524 else if (rowItemList[1 ] == " gridColor" )
462525 {
463- auto r = (unsigned char )rowItemList[2 ].toInt ();
464- auto g = (unsigned char )rowItemList[3 ].toInt ();
465- auto b = (unsigned char )rowItemList[4 ].toInt ();
466- auto a = 255 ;
467- type ->gridOptions .style ->color = Color (r, g, b, a);
526+ auto r = (unsigned char )rowItemList[2 ].toInt ();
527+ auto g = (unsigned char )rowItemList[3 ].toInt ();
528+ auto b = (unsigned char )rowItemList[4 ].toInt ();
529+ auto a = 255 ;
530+ currentType ->gridOptions .style ->color = Color (r, g, b, a);
468531 }
469532 else if (rowItemList[1 ] == " scaleFactor" )
470533 {
471- type ->vectorDataOptions ->scale = rowItemList[2 ].toInt ();
534+ currentType ->vectorDataOptions ->scale = rowItemList[2 ].toInt ();
472535 }
473536 else if (rowItemList[1 ] == " scaleToBlockSize" )
474537 {
475- type ->valueDataOptions ->scaleToBlockSize = (rowItemList[2 ] == " 1" );
538+ currentType ->valueDataOptions ->scaleToBlockSize = (rowItemList[2 ] == " 1" );
476539 }
477540 else if (rowItemList[1 ] == " seq-specs" )
478541 {
@@ -488,6 +551,8 @@ void StatisticsFileCSV::readHeaderFromFile(StatisticsData &statisticsData)
488551 this ->framerate = rowItemList[6 ].toDouble ();
489552 }
490553 }
554+
555+ checkAndAddTypeToStatisticsData (statisticsData, currentType);
491556 }
492557 catch (const char *str)
493558 {
0 commit comments