1 /*=========================================================================
2 
3   Program: GDCM (Grassroots DICOM). A DICOM library
4 
5   Copyright (c) 2006-2011 Mathieu Malaterre
6   All rights reserved.
7   See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.
8 
9      This software is distributed WITHOUT ANY WARRANTY; without even
10      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11      PURPOSE.  See the above copyright notice for more information.
12 
13 =========================================================================*/
14 #include "gdcmSurfaceWriter.h"
15 #include "gdcmAttribute.h"
16 #include "gdcmUIDGenerator.h"
17 
18 namespace gdcm
19 {
20 
SurfaceWriter()21 SurfaceWriter::SurfaceWriter():
22   NumberOfSurfaces(0)
23 {
24 }
25 
26 SurfaceWriter::~SurfaceWriter()
27 = default;
28 
ComputeNumberOfSurfaces()29 void SurfaceWriter::ComputeNumberOfSurfaces()
30 {
31   std::vector< SmartPointer< Segment > >::const_iterator  it    = Segments.begin();
32   std::vector< SmartPointer< Segment > >::const_iterator  itEnd = Segments.end();
33   for (; it != itEnd; it++)
34   {
35     NumberOfSurfaces += (*it)->GetSurfaceCount();
36   }
37 }
38 
GetNumberOfSurfaces()39 unsigned long SurfaceWriter::GetNumberOfSurfaces()
40 {
41   if (NumberOfSurfaces == 0)
42   {
43     ComputeNumberOfSurfaces();
44   }
45 
46   return NumberOfSurfaces;
47 }
48 
SetNumberOfSurfaces(const unsigned long nb)49 void SurfaceWriter::SetNumberOfSurfaces(const unsigned long nb)
50 {
51   NumberOfSurfaces = nb;
52 }
53 
PrepareWrite()54 bool SurfaceWriter::PrepareWrite()
55 {
56   if( !SegmentWriter::PrepareWrite() )
57   {
58     return false;
59   }
60 
61   File &                 file = GetFile();
62   DataSet &              ds   = file.GetDataSet();
63 
64   FileMetaInformation &  fmi  = file.GetHeader();
65   const TransferSyntax & ts   = fmi.GetDataSetTransferSyntax();
66   assert( ts.IsExplicit() || ts.IsImplicit() );
67 
68   // Number Of Surface
69   const unsigned long     nbSurfaces = this->GetNumberOfSurfaces();
70   if (nbSurfaces == 0)
71   {
72     gdcmErrorMacro( "No surface to write" );
73     return false;
74   }
75   Attribute<0x0066, 0x0001> numberOfSurfaces;
76   numberOfSurfaces.SetValue( (unsigned int)nbSurfaces );
77   ds.Replace( numberOfSurfaces.GetAsDataElement() );
78 
79   // Surface Sequence
80   SmartPointer<SequenceOfItems> surfacesSQ;
81   if( !ds.FindDataElement( Tag(0x0066, 0x0002) ) )
82   {
83     surfacesSQ = new SequenceOfItems;
84     DataElement detmp( Tag(0x0066, 0x0002) );
85     detmp.SetVR( VR::SQ );
86     detmp.SetValue( *surfacesSQ );
87     detmp.SetVLToUndefined();
88     ds.Insert( detmp );
89   }
90   surfacesSQ = ds.GetDataElement( Tag(0x0066, 0x0002) ).GetValueAsSQ();
91   surfacesSQ->SetLengthToUndefined();
92 
93   // Fill the Surface Sequence
94   {
95     const size_t nbItems    = surfacesSQ->GetNumberOfItems();
96     if (nbItems < nbSurfaces)
97     {
98       const size_t diff           = nbSurfaces - nbItems;
99       const size_t nbOfItemToMake = (diff > 0?diff:0);
100       for(unsigned int i = 1; i <= nbOfItemToMake; ++i)
101       {
102         Item item;
103         item.SetVLToUndefined();
104         surfacesSQ->AddItem(item);
105       }
106     }
107   }
108   // else Should I remove items?
109 
110   std::vector< SmartPointer< Segment > >                  segments  = this->GetSegments();
111   std::vector< SmartPointer< Segment > >::const_iterator  it0        = segments.begin();
112   std::vector< SmartPointer< Segment > >::const_iterator  it0End     = segments.end();
113   unsigned int                                            numSegment= 1;
114   unsigned int                                            numSurface= 1;
115   for (; it0 != it0End; it0++)
116   {
117     SmartPointer< Segment > segment = *it0;
118     assert( segment );
119 
120     std::vector< SmartPointer< Surface > >                  surfaces  = segment->GetSurfaces();
121     std::vector< SmartPointer< Surface > >::const_iterator  it1        = surfaces.begin();
122     std::vector< SmartPointer< Surface > >::const_iterator  it1End     = surfaces.end();
123     for (; it1 != it1End; it1++)
124     {
125       SmartPointer< Surface > surface = *it1;
126       assert( surface );
127 
128       Item &    surfaceItem = surfacesSQ->GetItem( numSurface );
129       DataSet & surfaceDS   = surfaceItem.GetNestedDataSet();
130 
131       // Recommended Display Grayscale Value
132       Attribute<0x0062, 0x000C> recommendedDisplayGrayscaleValue;
133       recommendedDisplayGrayscaleValue.SetValue( surface->GetRecommendedDisplayGrayscaleValue() );
134       surfaceDS.Replace( recommendedDisplayGrayscaleValue.GetAsDataElement() );
135 
136       // Recommended Display CIELab Value
137       Attribute<0x0062, 0x000D> recommendedDisplayCIELabValue;
138       recommendedDisplayCIELabValue.SetValues( surface->GetRecommendedDisplayCIELabValue(), 3 );
139       surfaceDS.Replace( recommendedDisplayCIELabValue.GetAsDataElement() );
140 
141       // Surface Number (Type 1)
142       Attribute<0x0066, 0x0003> surfaceNumberAt;
143       unsigned long surfaceNumber = surface->GetSurfaceNumber();
144       if (surfaceNumber == 0)
145         surfaceNumber = numSurface;
146       surfaceNumberAt.SetValue( (unsigned int)surfaceNumber );
147       surfaceDS.Replace( surfaceNumberAt.GetAsDataElement() );
148 
149       // Surface Comments (Type 3)
150       const char * surfaceComments = surface->GetSurfaceComments();
151       if (strcmp(surfaceComments, "") != 0)
152       {
153         Attribute<0x0066, 0x0004> surfaceCommentsAt;
154         surfaceCommentsAt.SetValue( surfaceComments );
155         surfaceDS.Replace( surfaceCommentsAt.GetAsDataElement() );
156       }
157 
158       // Surface Processing
159       const bool surfaceProcessing = surface->GetSurfaceProcessing();
160       Attribute<0x0066, 0x0009> surfaceProcessingAt;
161       surfaceProcessingAt.SetValue( (surfaceProcessing ? "YES" : "NO") );
162       surfaceDS.Replace( surfaceProcessingAt.GetAsDataElement() );
163 
164       if (surfaceProcessing)
165       {
166         Attribute<0x0066, 0x000A> surfaceProcessingRatioAt;
167         surfaceProcessingRatioAt.SetValue( surface->GetSurfaceProcessingRatio() );
168         surfaceDS.Replace( surfaceProcessingRatioAt.GetAsDataElement() );
169 
170         const char * surfaceProcessingDescription = surface->GetSurfaceProcessingDescription();
171         if (strcmp(surfaceProcessingDescription, "") != 0)
172         {
173           Attribute<0x0066, 0x000B> surfaceProcessingDescriptionAt;
174           surfaceProcessingDescriptionAt.SetValue( surfaceProcessingDescription );
175           surfaceDS.Replace( surfaceProcessingDescriptionAt.GetAsDataElement() );
176         }
177 
178         //*****   Surface Processing Algorithm Identification Sequence    *****//
179         {
180           SmartPointer<SequenceOfItems> processingAlgoIdSQ;
181           const Tag processingAlgoIdTag(0x0066, 0x0035);
182           if( !surfaceDS.FindDataElement( processingAlgoIdTag ) )
183           {
184             processingAlgoIdSQ = new SequenceOfItems;
185             DataElement detmp( processingAlgoIdTag );
186             detmp.SetVR( VR::SQ );
187             detmp.SetValue( *processingAlgoIdSQ );
188             detmp.SetVLToUndefined();
189             surfaceDS.Insert( detmp );
190           }
191           processingAlgoIdSQ = surfaceDS.GetDataElement( processingAlgoIdTag ).GetValueAsSQ();
192           processingAlgoIdSQ->SetLengthToUndefined();
193 
194           if (processingAlgoIdSQ->GetNumberOfItems() < 1) // One item shall be permitted
195           {
196             Item item;
197             item.SetVLToUndefined();
198             processingAlgoIdSQ->AddItem(item);
199           }
200 
201           Item &    processingAlgoIdItem  = processingAlgoIdSQ->GetItem(1);
202           DataSet & processingAlgoIdDS    = processingAlgoIdItem.GetNestedDataSet();
203 
204           //*****   Algorithm Family Code Sequence    *****//
205           //See: PS.3.3 Table 8.8-1 and PS 3.16 Context ID 7162
206           {
207             const SegmentHelper::BasicCodedEntry & processingAlgo = surface->GetProcessingAlgorithm();
208             if (processingAlgo.IsEmpty())
209             {
210               gdcmWarningMacro("Surface processing algorithm family not specified or incomplete");
211             }
212 
213             SmartPointer<SequenceOfItems> algoFamilyCodeSQ;
214             const Tag algoFamilyCodeTag(0x0066, 0x002F);
215             if( !processingAlgoIdDS.FindDataElement( algoFamilyCodeTag ) )
216             {
217               algoFamilyCodeSQ = new SequenceOfItems;
218               DataElement detmp( algoFamilyCodeTag );
219               detmp.SetVR( VR::SQ );
220               detmp.SetValue( *algoFamilyCodeSQ );
221               detmp.SetVLToUndefined();
222               processingAlgoIdDS.Insert( detmp );
223             }
224             algoFamilyCodeSQ = processingAlgoIdDS.GetDataElement( algoFamilyCodeTag ).GetValueAsSQ();
225             algoFamilyCodeSQ->SetLengthToUndefined();
226 
227             // Fill the Algorithm Family Code Sequence
228             if (algoFamilyCodeSQ->GetNumberOfItems() < 1)
229             {
230               Item item;
231               item.SetVLToUndefined();
232               algoFamilyCodeSQ->AddItem(item);
233             }
234 
235             Item &    algoFamilyCodeItem  = algoFamilyCodeSQ->GetItem(1);
236             DataSet & algoFamilyCodeDS    = algoFamilyCodeItem.GetNestedDataSet();
237 
238             //*****   CODE SEQUENCE MACRO ATTRIBUTES   *****//
239             {
240               // Code Value (Type 1)
241               Attribute<0x0008, 0x0100> codeValueAt;
242               codeValueAt.SetValue( processingAlgo.CV );
243               algoFamilyCodeDS.Replace( codeValueAt.GetAsDataElement() );
244 
245               // Coding Scheme (Type 1)
246               Attribute<0x0008, 0x0102> codingSchemeAt;
247               codingSchemeAt.SetValue( processingAlgo.CSD );
248               algoFamilyCodeDS.Replace( codingSchemeAt.GetAsDataElement() );
249 
250               // Code Meaning (Type 1)
251               Attribute<0x0008, 0x0104> codeMeaningAt;
252               codeMeaningAt.SetValue( processingAlgo.CM );
253               algoFamilyCodeDS.Replace( codeMeaningAt.GetAsDataElement() );
254             }
255           }
256         }
257       }
258 
259       // Presentation Opacity
260       Attribute<0x0066, 0x000C> presentationOpacity;
261       presentationOpacity.SetValue( surface->GetRecommendedPresentationOpacity() );
262       surfaceDS.Replace( presentationOpacity.GetAsDataElement() );
263 
264       // Presentation Type
265       Attribute<0x0066, 0x000D> presentationType;
266       const char * reconmmendedPresentationType = Surface::GetVIEWTypeString( surface->GetRecommendedPresentationType() );
267       if (reconmmendedPresentationType != nullptr)
268         presentationType.SetValue( reconmmendedPresentationType );
269       else
270         presentationType.SetValue( Surface::GetVIEWTypeString(Surface::SURFACE) );  // Is it the right thing to do?
271       surfaceDS.Replace( presentationType.GetAsDataElement() );
272 
273       // Finite Volume
274       Attribute<0x0066, 0x000E> finiteVolumeAt;
275       Surface::STATES finiteVolume = surface->GetFiniteVolume();
276       if (finiteVolume == Surface::STATES_END)
277         finiteVolume = Surface::UNKNOWN;
278       finiteVolumeAt.SetValue( Surface::GetSTATESString( finiteVolume ) );
279       surfaceDS.Replace( finiteVolumeAt.GetAsDataElement() );
280 
281       // Manifold
282       Attribute<0x0066, 0x0010> manifoldAt;
283       Surface::STATES manifold = surface->GetManifold();
284       if (manifold == Surface::STATES_END)
285         manifold = Surface::UNKNOWN;
286       manifoldAt.SetValue( Surface::GetSTATESString( manifold ) );
287       surfaceDS.Replace( manifoldAt.GetAsDataElement() );
288 
289       //******    Surface Points    *****//
290       //        (0066,0011) SQ (Sequence with undefined length #=1)     # u/l, 1 Surface Points Sequence
291       //          (fffe,e000) na (Item with undefined length #=1)         # u/l, 1 Item
292       //            (0066,0015) UL                                         #  0, 1 Number Of Surface Points
293       //            (0066,0016) OW                                         #  0, 1 Point Coordinates Data
294       //          (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem
295       //        (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem
296       if ( !PrepareWritePointMacro(surface, surfaceDS, ts) )
297         return false;
298 
299       //******    Surface Points Normals    *****//
300       //        (0066,0012) SQ (Sequence with undefined length #=1)     # u/l, 1 Surface Points Sequence
301       //          (fffe,e000) na (Item with undefined length #=1)         # u/l, 1 Item
302       //            (0066,001e) UL                                         #  0, 1 Number of Vectors
303       //            (0066,001f) US                                         #  0, 1 Vector Dimensionality
304       //            (0066,0021) OF                                         #  0, 1_n Vector Coordinate Data
305       //          (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem
306       //        (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem
307       const unsigned long           numberofvectors = surface->GetNumberOfVectors();
308       SmartPointer< MeshPrimitive > meshPrimitive   = surface->GetMeshPrimitive();
309       const MeshPrimitive::MPType   primitiveType   = meshPrimitive->GetPrimitiveType();
310       if (numberofvectors > 0
311        && primitiveType != MeshPrimitive::TRIANGLE_STRIP
312        && primitiveType != MeshPrimitive::TRIANGLE_FAN)
313       {
314         SmartPointer<SequenceOfItems> surfacePointsNormalsSQ;
315         if( !surfaceDS.FindDataElement( Tag(0x0066, 0x0012) ) )
316         {
317           surfacePointsNormalsSQ = new SequenceOfItems;
318           DataElement detmp( Tag(0x0066, 0x0012) );
319           detmp.SetVR( VR::SQ );
320           detmp.SetValue( *surfacePointsNormalsSQ );
321           detmp.SetVLToUndefined();
322           surfaceDS.Insert( detmp );
323         }
324         surfacePointsNormalsSQ = surfaceDS.GetDataElement( Tag(0x0066, 0x0012) ).GetValueAsSQ();
325         surfacePointsNormalsSQ->SetLengthToUndefined();
326 
327         if (surfacePointsNormalsSQ->GetNumberOfItems() < 1)  // One item shall be permitted
328         {
329           Item item;
330           item.SetVLToUndefined();
331           surfacePointsNormalsSQ->AddItem(item);
332         }
333 
334         Item &    surfacePointsNormalsItem = surfacePointsNormalsSQ->GetItem(1);
335         DataSet & surfacePointsNormalsDS   = surfacePointsNormalsItem.GetNestedDataSet();
336 
337         // Number of Vectors
338         Attribute<0x0066, 0x001E> numberOfVectors;
339         numberOfVectors.SetValue( (unsigned int)surface->GetNumberOfVectors() );
340         surfacePointsNormalsDS.Replace( numberOfVectors.GetAsDataElement() );
341 
342         // Vector Dimensionality
343         Attribute<0x0066, 0x001F> vectorDimensionalityAt;
344         unsigned short vectorDimensionality = surface->GetVectorDimensionality();
345         assert( vectorDimensionality );
346         vectorDimensionalityAt.SetValue( vectorDimensionality );
347         surfacePointsNormalsDS.Replace( vectorDimensionalityAt.GetAsDataElement() );
348 
349         // Vector Accuracy (Type 3)
350         Attribute<0x0066, 0x0020> vectorAccuracyAt;
351         const float * vectorAccuracy = surface->GetVectorAccuracy();
352         if (vectorAccuracy != nullptr)
353         {
354           vectorAccuracyAt.SetValues( vectorAccuracy, vectorDimensionality );
355           surfacePointsNormalsDS.Replace( vectorAccuracyAt.GetAsDataElement() );
356         }
357 
358         // Vector Coordinate Data
359         DataElement vectorCoordDataDE( Tag(0x0066, 0x0021) );
360         vectorCoordDataDE.SetVR( VR::OF );
361         const Value & vectorCoordinateDataValue = surface->GetVectorCoordinateData().GetValue();
362         assert( &vectorCoordinateDataValue );
363         vectorCoordDataDE.SetValue( vectorCoordinateDataValue );
364 
365         const ByteValue *bv = vectorCoordDataDE.GetByteValue();
366         VL vl;
367         if ( bv )
368           vl = bv->GetLength();
369         else
370           vl.SetToUndefined();
371         vectorCoordDataDE.SetVL( vl );
372 
373         if ( ts.IsExplicit() )
374           vectorCoordDataDE.SetVR( VR::OF );
375 
376         surfacePointsNormalsDS.Replace( vectorCoordDataDE );
377       }
378       else if (numberofvectors > 0)
379       {
380         gdcmWarningMacro("Triangle strip or fan have no surface points normals");
381       }
382 
383       //******    Surface Mesh Primitives    *****//
384       //        Two exemples :
385       //        (0066,0013) SQ (Sequence with undefined length #=1)     # u/l, 1 Surface Mesh Primitives Sequence
386       //          (fffe,e000) na (Item with undefined length #=1)         # u/l, 1 Item
387       //            (0066,0042) OL                                         #  0, 1 Long Edge Point Index List
388       //          (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem
389       //        (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem
390       //
391       //              OR
392       //
393       //        (0066,0013) SQ (Sequence with undefined length #=1)     # u/l, 1 Surface Mesh Primitives Sequence
394       //          (fffe,e000) na (Item with undefined length #=1)         # u/l, 1 Item
395       //            (0066,0026) SQ (Sequence with undefined length #=1)     # u/l, 1 // Triangle Strip Sequence
396       //              (fffe,e000) na (Item with undefined length #=1)         # u/l, 1 Item
397       //                (0066,0040) OL                                         #  0, 1 // Long Primitive Point Index List
398       //              (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem
399       //                                            ...
400       //              (fffe,e000) na (Item with undefined length #=1)         # u/l, 1 Item
401       //                (0066,0040) OL                                         #  0, 1 // Long Primitive Point Index List
402       //              (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem
403       //            (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem
404       //          (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem
405       //        (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem
406 
407       // Surface Mesh Primitives Sequence
408       {
409         SmartPointer<SequenceOfItems> surfaceMeshPrimitivesSQ;
410         if( !surfaceDS.FindDataElement( Tag(0x0066, 0x0013) ) )
411         {
412           surfaceMeshPrimitivesSQ = new SequenceOfItems;
413           DataElement detmp( Tag(0x0066, 0x0013) );
414           detmp.SetVR( VR::SQ );
415           detmp.SetValue( *surfaceMeshPrimitivesSQ );
416           detmp.SetVLToUndefined();
417           surfaceDS.Insert( detmp );
418         }
419         surfaceMeshPrimitivesSQ = surfaceDS.GetDataElement( Tag(0x0066, 0x0013) ).GetValueAsSQ();
420         surfaceMeshPrimitivesSQ->SetLengthToUndefined();
421 
422         if (surfaceMeshPrimitivesSQ->GetNumberOfItems() < 1)  // One itme shall be permitted
423         {
424           Item item;
425           item.SetVLToUndefined();
426           surfaceMeshPrimitivesSQ->AddItem(item);
427         }
428 
429         Item &    surfaceMeshPrimitivesItem = surfaceMeshPrimitivesSQ->GetItem(1);
430         DataSet & surfaceMeshPrimitivesDS   = surfaceMeshPrimitivesItem.GetNestedDataSet();
431 
432         //*****   Handle "Typed" Point Index List   *****//
433         bool      insertInSQ = false;
434 
435         // Primitive Point Index List
436         Tag         typedPrimitiveTag;
437         typedPrimitiveTag.SetGroup(0x0066);
438         DataSet &   pointIndexListDS0  = surfaceMeshPrimitivesDS;
439 
440         switch (primitiveType)
441         {
442         case MeshPrimitive::VERTEX:
443           // Long Vertex Point Index List
444           typedPrimitiveTag.SetElement(0x0043);
445           break;
446         case MeshPrimitive::EDGE:
447           // Long Edge Point Index List
448           typedPrimitiveTag.SetElement(0x0042);
449           break;
450         case MeshPrimitive::TRIANGLE:
451           // Long Triangle Point Index List
452           typedPrimitiveTag.SetElement(0x0041);
453           break;
454         case MeshPrimitive::TRIANGLE_STRIP:
455         case MeshPrimitive::TRIANGLE_FAN:
456         case MeshPrimitive::LINE:
457         case MeshPrimitive::FACET:
458           // Long Primitive Point Index List
459           typedPrimitiveTag.SetElement(0x0040);
460           insertInSQ = true;
461           break;
462         default:
463           gdcmErrorMacro( "Unknown surface mesh primitives type" );
464           return false;
465         }
466 
467         if (insertInSQ)
468         {
469           // Handled "complex" mesh primitives
470 
471           Tag typedSequenceTag;
472           typedSequenceTag.SetGroup(0x0066);
473           switch (primitiveType)
474           {
475           case MeshPrimitive::TRIANGLE_STRIP:
476             // Triangle Strip Sequence
477             typedSequenceTag.SetElement(0x0026);
478             break;
479           case MeshPrimitive::TRIANGLE_FAN:
480             // Triangle Fan Sequence
481             typedSequenceTag.SetElement(0x0027);
482             break;
483           case MeshPrimitive::LINE:
484             // Line Sequence
485             typedSequenceTag.SetElement(0x0028);
486             break;
487           case MeshPrimitive::FACET:
488             // Facet Sequence
489             typedSequenceTag.SetElement(0x0034);
490             break;
491           default:
492             gdcmErrorMacro( "Unknown surface mesh primitives type" );
493             return false;
494           }
495 
496           // "Typed" Sequence
497           SmartPointer<SequenceOfItems> typedSequenceSQ;
498           if( !surfaceMeshPrimitivesDS.FindDataElement( typedSequenceTag ) )
499           {
500             typedSequenceSQ = new SequenceOfItems;
501             DataElement detmp( typedSequenceTag );
502             detmp.SetVR( VR::SQ );
503             detmp.SetValue( *typedSequenceSQ );
504             detmp.SetVLToUndefined();
505             surfaceMeshPrimitivesDS.Insert( detmp );
506           }
507           typedSequenceSQ = surfaceMeshPrimitivesDS.GetDataElement( typedSequenceTag ).GetValueAsSQ();
508           typedSequenceSQ->SetLengthToUndefined();
509 
510           // Fill the Segment Sequence
511           const unsigned int              numberOfPrimitives  = meshPrimitive->GetNumberOfPrimitivesData();
512           assert( numberOfPrimitives );
513           const size_t nbItems             = typedSequenceSQ->GetNumberOfItems();
514           if (nbItems < numberOfPrimitives)
515           {
516             const size_t diff           = numberOfPrimitives - nbItems;
517             const size_t nbOfItemToMake = (diff > 0?diff:0);
518             for(unsigned int i = 1; i <= nbOfItemToMake; ++i)
519             {
520               Item item;
521               item.SetVLToUndefined();
522               typedSequenceSQ->AddItem(item);
523             }
524           }
525           // else Should I remove items?
526 
527           const MeshPrimitive::PrimitivesData &         primitivesData= meshPrimitive->GetPrimitivesData();
528           MeshPrimitive::PrimitivesData::const_iterator it            = primitivesData.begin();
529           MeshPrimitive::PrimitivesData::const_iterator itEnd         = primitivesData.end();
530           unsigned int                                  i             = 1;
531           for (; it != itEnd; it++)
532           {
533             Item &    typedSequenceItem = typedSequenceSQ->GetItem(i++);
534             DataSet & pointIndexListDS  = typedSequenceItem.GetNestedDataSet();
535 
536             // "Typed" Point Index List
537             DataElement typedPointIndexListDE( typedPrimitiveTag );
538 
539             const Value & pointIndexListValue = it->GetValue();
540             assert( &pointIndexListValue );
541             typedPointIndexListDE.SetValue( pointIndexListValue );
542 
543             const ByteValue * pointIndexListBV = typedPointIndexListDE.GetByteValue();
544             VL pointIndexListVL;
545             if( pointIndexListBV )
546             {
547               pointIndexListVL = pointIndexListBV->GetLength();
548             }
549             else
550             {
551               pointIndexListVL.SetToUndefined();
552             }
553             typedPointIndexListDE.SetVL( pointIndexListVL );
554 
555             if ( ts.IsExplicit() )
556               typedPointIndexListDE.SetVR( VR::OL );
557 
558             pointIndexListDS.Replace( typedPointIndexListDE );
559           }
560         }
561         else
562         {
563           // Handled "simple" mesh primitives
564 
565           // "Typed" Point Index List
566           DataElement   typedPointIndexListDE( typedPrimitiveTag );
567 
568           const Value & pointIndexListValue = meshPrimitive->GetPrimitiveData().GetValue();
569           assert( &pointIndexListValue );
570           typedPointIndexListDE.SetValue( pointIndexListValue );
571 
572           const ByteValue * pointIndexListBV = typedPointIndexListDE.GetByteValue();
573           VL pointIndexListVL;
574           if ( pointIndexListBV )
575             pointIndexListVL = pointIndexListBV->GetLength();
576           else
577             pointIndexListVL.SetToUndefined();
578           typedPointIndexListDE.SetVL( pointIndexListVL );
579 
580           if ( ts.IsExplicit() )
581             typedPointIndexListDE.SetVR( VR::OL );
582 
583           pointIndexListDS0.Replace( typedPointIndexListDE );
584         }
585 
586         //*****   Add empty values in unused but required tags (Type 2)   *****//
587 
588         DataElement emptyOLDE;
589         emptyOLDE.SetVLToUndefined();
590         emptyOLDE.SetVR( VR::OL );
591         SmartPointer<ByteValue> emptyValueOW = new ByteValue;
592         emptyOLDE.SetValue(*emptyValueOW);
593 
594         // Long Vertex Point Index List ( Type 2 )
595         Tag vertexPointIndexListTag(0x0066, 0x0043);
596         if( !surfaceMeshPrimitivesDS.FindDataElement( vertexPointIndexListTag ) )
597         {
598           emptyOLDE.SetTag( vertexPointIndexListTag );
599           surfaceMeshPrimitivesDS.Insert( emptyOLDE );
600         }
601 
602         // Long Edge Point Index List ( Type 2 )
603         Tag edgePointIndexListTag(0x0066, 0x0042);
604         if( !surfaceMeshPrimitivesDS.FindDataElement( edgePointIndexListTag ) )
605         {
606           emptyOLDE.SetTag( edgePointIndexListTag );
607           surfaceMeshPrimitivesDS.Insert( emptyOLDE );
608         }
609 
610         // Long Triangle Point Index List ( Type 2 )
611         Tag trianglePointIndexListTag(0x0066, 0x0041);
612         if( !surfaceMeshPrimitivesDS.FindDataElement( trianglePointIndexListTag ) )
613         {
614           emptyOLDE.SetTag( trianglePointIndexListTag );
615           surfaceMeshPrimitivesDS.Insert( emptyOLDE );
616         }
617 
618         DataElement emptySQDE;
619         emptySQDE.SetVLToUndefined();
620         emptySQDE.SetVR( VR::SQ );
621         SmartPointer<SequenceOfItems> emptySequenceSQ = new SequenceOfItems;
622         emptySQDE.SetValue(*emptySequenceSQ);
623 
624         // Triangle Strip Sequence ( Type 2 )
625         Tag triangleStripSequenceTag(0x0066, 0x0026);
626         if( !surfaceMeshPrimitivesDS.FindDataElement( triangleStripSequenceTag ) )
627         {
628           emptySQDE.SetTag( triangleStripSequenceTag );
629           surfaceMeshPrimitivesDS.Insert( emptySQDE );
630         }
631 
632         // Triangle Fan Sequence ( Type 2 )
633         Tag triangleFanSequenceTag(0x0066, 0x0027);
634         if( !surfaceMeshPrimitivesDS.FindDataElement( triangleFanSequenceTag ) )
635         {
636           emptySQDE.SetTag( triangleFanSequenceTag );
637           surfaceMeshPrimitivesDS.Insert( emptySQDE );
638         }
639 
640         // Line Sequence ( Type 2 )
641         Tag lineSequenceTag(0x0066, 0x0028);
642         if( !surfaceMeshPrimitivesDS.FindDataElement( lineSequenceTag ) )
643         {
644           emptySQDE.SetTag( lineSequenceTag );
645           surfaceMeshPrimitivesDS.Insert( emptySQDE );
646         }
647 
648         // Facet Sequence ( Type 2 )
649         Tag facetSequenceTag(0x0066, 0x0034);
650         if( !surfaceMeshPrimitivesDS.FindDataElement( facetSequenceTag ) )
651         {
652           emptySQDE.SetTag( facetSequenceTag );
653           surfaceMeshPrimitivesDS.Insert( emptySQDE );
654         }
655 
656       }
657       ++numSurface;
658     }
659 
660 
661     //*****   Segment Sequence    *****//
662     SmartPointer<SequenceOfItems>   segmentsSQ      = ds.GetDataElement( Tag(0x0062, 0x0002) ).GetValueAsSQ();
663     Item &                          segmentIt       = segmentsSQ->GetItem( numSegment++ );
664     DataSet &                       segmentDS       = segmentIt.GetNestedDataSet();
665 
666     //*****   Referenced Surface Sequence    *****//
667     SmartPointer<SequenceOfItems>   refSurfaceSQ    = segmentDS.GetDataElement( Tag(0x0066, 0x002B) ).GetValueAsSQ();
668     SequenceOfItems::Iterator       itRefSurface    = refSurfaceSQ->Begin();
669     SequenceOfItems::Iterator       itEndRefSurface = refSurfaceSQ->End();
670     unsigned int                    idxSurface      = 0;
671     for (; itRefSurface != itEndRefSurface; itRefSurface++)
672     {
673       DataSet &                     refSurfaceDS    = itRefSurface->GetNestedDataSet();
674       SmartPointer< Surface >       surface         = segment->GetSurface( idxSurface++ );
675 
676       //*****   Segment Surface Generation Algorithm Identification Sequence    *****//
677       {
678         SmartPointer<SequenceOfItems> segmentsAlgoIdSQ;
679         const Tag segmentsAlgoIdTag(0x0066, 0x002D);
680         if( !refSurfaceDS.FindDataElement( segmentsAlgoIdTag ) )
681         {
682           segmentsAlgoIdSQ = new SequenceOfItems;
683           DataElement detmp( segmentsAlgoIdTag );
684           detmp.SetVR( VR::SQ );
685           detmp.SetValue( *segmentsAlgoIdSQ );
686           detmp.SetVLToUndefined();
687           refSurfaceDS.Insert( detmp );
688         }
689         segmentsAlgoIdSQ = refSurfaceDS.GetDataElement( segmentsAlgoIdTag ).GetValueAsSQ();
690         segmentsAlgoIdSQ->SetLengthToUndefined();
691 
692         if (segmentsAlgoIdSQ->GetNumberOfItems() < 1)
693         {
694           Item item;
695           item.SetVLToUndefined();
696           segmentsAlgoIdSQ->AddItem(item);
697         }
698 
699         Item &    segmentsAlgoIdItem  = segmentsAlgoIdSQ->GetItem(1);
700         DataSet & segmentsAlgoIdDS    = segmentsAlgoIdItem.GetNestedDataSet();
701 
702         //*****   Algorithm Family Code Sequence    *****//
703         //See: PS.3.3 Table 8.8-1 and PS 3.16 Context ID 7162
704         const SegmentHelper::BasicCodedEntry & algoFamily = surface->GetAlgorithmFamily();
705         if (algoFamily.IsEmpty())
706         {
707           gdcmWarningMacro("Segment surface generation algorithm family not specified or incomplete");
708         }
709 
710           SmartPointer<SequenceOfItems> algoFamilyCodeSQ;
711           const Tag algoFamilyCodeTag(0x0066, 0x002F);
712 
713           if( !segmentsAlgoIdDS.FindDataElement( algoFamilyCodeTag ) )
714           {
715             algoFamilyCodeSQ = new SequenceOfItems;
716             DataElement detmp( algoFamilyCodeTag );
717             detmp.SetVR( VR::SQ );
718             detmp.SetValue( *algoFamilyCodeSQ );
719             detmp.SetVLToUndefined();
720             segmentsAlgoIdDS.Insert( detmp );
721           }
722 
723           algoFamilyCodeSQ = segmentsAlgoIdDS.GetDataElement( algoFamilyCodeTag ).GetValueAsSQ();
724           algoFamilyCodeSQ->SetLengthToUndefined();
725 
726           // Fill the Algorithm Family Code Sequence
727           if (algoFamilyCodeSQ->GetNumberOfItems() < 1)
728           {
729             Item item;
730             item.SetVLToUndefined();
731             algoFamilyCodeSQ->AddItem(item);
732           }
733 
734           Item &    algoFamilyCodeItem  = algoFamilyCodeSQ->GetItem(1);
735           DataSet & algoFamilyCodeDS    = algoFamilyCodeItem.GetNestedDataSet();
736 
737           //*****   CODE SEQUENCE MACRO ATTRIBUTES   *****//
738           {
739             // Code Value (Type 1)
740             Attribute<0x0008, 0x0100> codeValueAt;
741             codeValueAt.SetValue( algoFamily.CV );
742             algoFamilyCodeDS.Replace( codeValueAt.GetAsDataElement() );
743 
744             // Coding Scheme (Type 1)
745             Attribute<0x0008, 0x0102> codingSchemeAt;
746             codingSchemeAt.SetValue( algoFamily.CSD );
747             algoFamilyCodeDS.Replace( codingSchemeAt.GetAsDataElement() );
748 
749             // Code Meaning (Type 1)
750             Attribute<0x0008, 0x0104> codeMeaningAt;
751             codeMeaningAt.SetValue( algoFamily.CM );
752             algoFamilyCodeDS.Replace( codeMeaningAt.GetAsDataElement() );
753           }
754 
755         // Algorithm Version
756         const char * algorithmVersion = surface->GetAlgorithmVersion();
757         if (strcmp(algorithmVersion, "") != 0)
758         {
759           gdcmWarningMacro("No algorithm version specified");
760         }
761         Attribute<0x0066, 0x0031> algorithmVersionAt;
762         algorithmVersionAt.SetValue( algorithmVersion );
763         segmentsAlgoIdDS.Replace( algorithmVersionAt.GetAsDataElement() );
764 
765         // Algorithm Name
766         const char * algorithmName = surface->GetAlgorithmName();
767         if (strcmp(algorithmName, "") != 0)
768         {
769           gdcmWarningMacro("No algorithm name specified");
770         }
771         Attribute<0x0066, 0x0036> algorithmNameAt;
772         algorithmNameAt.SetValue( algorithmName );
773         segmentsAlgoIdDS.Replace( algorithmNameAt.GetAsDataElement() );
774       }
775     }
776 
777   }
778 
779   //**  Complete the file   **//
780   // Is SOP Class UID defined?
781   if( !ds.FindDataElement( Tag(0x0008, 0x0016) ) )
782   {
783     const char * SOPClassUID = MediaStorage::GetMSString(MediaStorage::SurfaceSegmentationStorage);
784 
785     DataElement de( Tag(0x0008, 0x0016) );
786     VL::Type strlenSOPClassUID= (VL::Type)strlen(SOPClassUID);
787     de.SetByteValue( SOPClassUID, strlenSOPClassUID );
788     de.SetVR( Attribute<0x0008, 0x0016>::GetVR() );
789     ds.ReplaceEmpty( de );
790   }
791 
792   // Is SOP Instance UID defined?
793   if( !ds.FindDataElement( Tag(0x0008, 0x0018) ) )
794   {
795     UIDGenerator  UIDgen;
796     UIDgen.SetRoot( MediaStorage::GetMSString(MediaStorage::SurfaceSegmentationStorage) );
797     const char * SOPInstanceUID = UIDgen.Generate();
798 
799     DataElement de( Tag(0x0008, 0x0018) );
800     VL::Type strlenSOPInstanceUID= (VL::Type)strlen(SOPInstanceUID);
801     de.SetByteValue( SOPInstanceUID, strlenSOPInstanceUID );
802     de.SetVR( Attribute<0x0008, 0x0018>::GetVR() );
803     ds.ReplaceEmpty( de );
804   }
805 
806   fmi.Clear();
807   {
808     const char *tsuid = TransferSyntax::GetTSString( ts );
809     DataElement de( Tag(0x0002,0x0010) );
810     VL::Type strlenTSUID = (VL::Type)strlen(tsuid);
811     de.SetByteValue( tsuid, strlenTSUID );
812     de.SetVR( Attribute<0x0002, 0x0010>::GetVR() );
813     fmi.Replace( de );
814     fmi.SetDataSetTransferSyntax(ts);
815   }
816   fmi.FillFromDataSet( ds );
817 
818   return true;
819 }
820 
Write()821 bool SurfaceWriter::Write()
822 {
823   if( !PrepareWrite() )
824   {
825     return false;
826   }
827 
828   assert( Stream );
829   if( !Writer::Write() )
830   {
831     return false;
832   }
833 
834   return true;
835 }
836 
PrepareWritePointMacro(SmartPointer<Surface> surface,DataSet & surfaceDS,const TransferSyntax & ts)837 bool SurfaceWriter::PrepareWritePointMacro(SmartPointer< Surface > surface,
838                                            DataSet & surfaceDS,
839                                            const TransferSyntax & ts)
840 {
841   //******    Surface Points    *****//
842   //        (0066,0011) SQ (Sequence with undefined length #=1)     # u/l, 1 Surface Points Sequence
843   //          (fffe,e000) na (Item with undefined length #=1)         # u/l, 1 Item
844   //            (0066,0015) UL                                         #  0, 1 Number Of Surface Points
845   //            (0066,0016) OW                                         #  0, 1 Point Coordinates Data
846   //          (fffe,e00d) na (ItemDelimitationItem)                   #   0, 0 ItemDelimitationItem
847   //        (fffe,e0dd) na (SequenceDelimitationItem)               #   0, 0 SequenceDelimitationItem
848 
849   //*****   Surface Points Sequence   *****//
850   {
851     SmartPointer<SequenceOfItems> surfacePointsSq;
852     if( !surfaceDS.FindDataElement( Tag(0x0066, 0x0011) ) )
853     {
854       surfacePointsSq = new SequenceOfItems;
855       DataElement detmp( Tag(0x0066, 0x0011) );
856       detmp.SetVR( VR::SQ );
857       detmp.SetValue( *surfacePointsSq );
858       detmp.SetVLToUndefined();
859       surfaceDS.Insert( detmp );
860     }
861     surfacePointsSq = surfaceDS.GetDataElement( Tag(0x0066, 0x0011) ).GetValueAsSQ();
862     surfacePointsSq->SetLengthToUndefined();
863 
864     if (surfacePointsSq->GetNumberOfItems() < 1)  // One item shall be permitted
865     {
866       Item item;
867       item.SetVLToUndefined();
868       surfacePointsSq->AddItem(item);
869     }
870 
871     Item &    surfacePointsItem = surfacePointsSq->GetItem(1);
872     DataSet & surfacePointsDs   = surfacePointsItem.GetNestedDataSet();
873 
874     // Point Coordinates Data
875     DataElement pointCoordDataDE( Tag(0x0066, 0x0016) );
876     const Value & pointCoordinateDataValue = surface->GetPointCoordinatesData().GetValue();
877     assert( &pointCoordinateDataValue );
878     pointCoordDataDE.SetValue( pointCoordinateDataValue );
879 
880     const ByteValue *bv = pointCoordDataDE.GetByteValue();
881     VL vl;
882     if ( bv )
883       vl = bv->GetLength();
884     else
885       vl.SetToUndefined();
886     pointCoordDataDE.SetVL( vl );
887 
888     if ( ts.IsExplicit() )
889       pointCoordDataDE.SetVR( VR::OF );
890 
891     surfacePointsDs.Replace( pointCoordDataDE );
892 
893     // Number Of Surface Points
894     Attribute<0x0066, 0x0015> numberOfSurfacePointsAt;
895     unsigned long numberOfSurfacePoints = surface->GetNumberOfSurfacePoints();
896     if (numberOfSurfacePoints == 0)
897       numberOfSurfacePoints = bv->GetLength() / (VR::GetLength(VR::OF) * 3);
898     numberOfSurfacePointsAt.SetValue( (unsigned int)numberOfSurfacePoints );
899     surfacePointsDs.Replace( numberOfSurfacePointsAt.GetAsDataElement() );
900 
901     // Point Position Accuracy (Type 3)
902     Attribute<0x0066, 0x0017> pointPositionAccuracyAt;
903     const float * pointPositionAccuracy = surface->GetPointPositionAccuracy();
904     if (pointPositionAccuracy != nullptr)
905     {
906       pointPositionAccuracyAt.SetValues( pointPositionAccuracy );
907       surfacePointsDs.Replace( pointPositionAccuracyAt.GetAsDataElement() );
908     }
909 
910     // Mean Point Distance (Type 3)
911     Attribute<0x0066, 0x0018> meanPointDistanceAt;
912     float meanPointDistance = surface->GetMeanPointDistance();
913     if (meanPointDistance != 0) // FIXME: user can specified 0 value
914     {
915       meanPointDistanceAt.SetValue( meanPointDistance );
916       surfacePointsDs.Replace( meanPointDistanceAt.GetAsDataElement() );
917     }
918 
919     // Maximum Point Distance (Type 3)
920     Attribute<0x0066, 0x0019> maximumPointDistanceAt;
921     float maximumPointDistance = surface->GetMaximumPointDistance();
922     if (maximumPointDistance != 0) // FIXME: user can specified 0 value
923     {
924       maximumPointDistanceAt.SetValue( maximumPointDistance );
925       surfacePointsDs.Replace( maximumPointDistanceAt.GetAsDataElement() );
926     }
927 
928     // Point Bounding Box Coordinates (Type 3)
929     Attribute<0x0066, 0x001a> pointsBoundingBoxCoordinatesAt;
930     const float * pointsBoundingBoxCoordinates = surface->GetPointsBoundingBoxCoordinates();
931     if (pointsBoundingBoxCoordinates != nullptr)
932     {
933       pointsBoundingBoxCoordinatesAt.SetValues( pointsBoundingBoxCoordinates );
934       surfacePointsDs.Replace( pointsBoundingBoxCoordinatesAt.GetAsDataElement() );
935     }
936 
937     // Axis of Rotation (Type 3)
938     Attribute<0x0066, 0x001b> axisOfRotationAt;
939     const float * axisOfRotation = surface->GetAxisOfRotation();
940     if (axisOfRotation != nullptr)
941     {
942       axisOfRotationAt.SetValues( axisOfRotation );
943       surfacePointsDs.Replace( axisOfRotationAt.GetAsDataElement() );
944     }
945 
946     // Center of Rotation (Type 3)
947     Attribute<0x0066, 0x001c> centerOfRotationAt;
948     const float * centerOfRotation = surface->GetCenterOfRotation();
949     if (centerOfRotation != nullptr)
950     {
951       centerOfRotationAt.SetValues( centerOfRotation );
952       surfacePointsDs.Replace( centerOfRotationAt.GetAsDataElement() );
953     }
954 
955     return true;
956   }
957 }
958 
959 }
960