0033661: Data Exchange, Step Import - Tessellated GDTs are not imported
[occt.git] / src / Graphic3d / Graphic3d_ArrayOfPrimitives.cxx
1 // Created on: 2000-06-16
2 // Copyright (c) 2000-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 #include <Graphic3d_ArrayOfPrimitives.hxx>
16
17 #include <Graphic3d_ArrayOfPoints.hxx>
18 #include <Graphic3d_ArrayOfSegments.hxx>
19 #include <Graphic3d_ArrayOfPolylines.hxx>
20 #include <Graphic3d_ArrayOfTriangles.hxx>
21 #include <Graphic3d_ArrayOfTriangleStrips.hxx>
22 #include <Graphic3d_ArrayOfTriangleFans.hxx>
23 #include <Graphic3d_ArrayOfQuadrangles.hxx>
24 #include <Graphic3d_ArrayOfQuadrangleStrips.hxx>
25 #include <Graphic3d_ArrayOfPolygons.hxx>
26 #include <Graphic3d_AttribBuffer.hxx>
27 #include <Graphic3d_MutableIndexBuffer.hxx>
28
29 #include <NCollection_AlignedAllocator.hxx>
30 #include <TCollection_AsciiString.hxx>
31
32 #include <stdio.h>
33 #include <stdlib.h>
34
35 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ArrayOfPrimitives, Standard_Transient)
36
37 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ArrayOfPoints,           Graphic3d_ArrayOfPrimitives)
38 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ArrayOfSegments,         Graphic3d_ArrayOfPrimitives)
39 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ArrayOfPolylines,        Graphic3d_ArrayOfPrimitives)
40 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ArrayOfTriangles,        Graphic3d_ArrayOfPrimitives)
41 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ArrayOfTriangleStrips,   Graphic3d_ArrayOfPrimitives)
42 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ArrayOfTriangleFans,     Graphic3d_ArrayOfPrimitives)
43 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ArrayOfQuadrangles,      Graphic3d_ArrayOfPrimitives)
44 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ArrayOfQuadrangleStrips, Graphic3d_ArrayOfPrimitives)
45 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ArrayOfPolygons,         Graphic3d_ArrayOfPrimitives)
46
47 // =======================================================================
48 // function : CreateArray
49 // purpose  :
50 // =======================================================================
51 Handle(Graphic3d_ArrayOfPrimitives) Graphic3d_ArrayOfPrimitives::CreateArray (Graphic3d_TypeOfPrimitiveArray theType,
52                                                                               Standard_Integer theMaxVertexs,
53                                                                               Standard_Integer theMaxBounds,
54                                                                               Standard_Integer theMaxEdges,
55                                                                               Graphic3d_ArrayFlags theArrayFlags)
56 {
57   switch (theType)
58   {
59     case Graphic3d_TOPA_UNDEFINED:
60       return Handle(Graphic3d_ArrayOfPrimitives)();
61     case Graphic3d_TOPA_POINTS:
62       return new Graphic3d_ArrayOfPoints (theMaxVertexs, theArrayFlags);
63     case Graphic3d_TOPA_SEGMENTS:
64       return new Graphic3d_ArrayOfSegments (theMaxVertexs, theMaxEdges, theArrayFlags);
65     case Graphic3d_TOPA_POLYLINES:
66       return new Graphic3d_ArrayOfPolylines (theMaxVertexs, theMaxBounds, theMaxEdges, theArrayFlags);
67     case Graphic3d_TOPA_TRIANGLES:
68       return new Graphic3d_ArrayOfTriangles (theMaxVertexs, theMaxEdges, theArrayFlags);
69     case Graphic3d_TOPA_TRIANGLESTRIPS:
70       return new Graphic3d_ArrayOfTriangleStrips (theMaxVertexs, theMaxBounds, theArrayFlags);
71     case Graphic3d_TOPA_TRIANGLEFANS:
72       return new Graphic3d_ArrayOfTriangleFans (theMaxVertexs, theMaxBounds, theArrayFlags);
73     case Graphic3d_TOPA_LINES_ADJACENCY:
74     case Graphic3d_TOPA_LINE_STRIP_ADJACENCY:
75     case Graphic3d_TOPA_TRIANGLES_ADJACENCY:
76     case Graphic3d_TOPA_TRIANGLE_STRIP_ADJACENCY:
77       return new Graphic3d_ArrayOfPrimitives (theType, theMaxVertexs, theMaxBounds, theMaxEdges, theArrayFlags);
78     case Graphic3d_TOPA_QUADRANGLES:
79       return new Graphic3d_ArrayOfQuadrangles (theMaxVertexs, theMaxEdges, theArrayFlags);
80     case Graphic3d_TOPA_QUADRANGLESTRIPS:
81       return new Graphic3d_ArrayOfQuadrangleStrips (theMaxVertexs, theMaxBounds, theArrayFlags);
82     case Graphic3d_TOPA_POLYGONS:
83       return new Graphic3d_ArrayOfPolygons (theMaxVertexs, theMaxBounds, theMaxEdges, theArrayFlags);
84   }
85   return Handle(Graphic3d_ArrayOfPrimitives)();
86 }
87
88 // =======================================================================
89 // function : init
90 // purpose  :
91 // =======================================================================
92 void Graphic3d_ArrayOfPrimitives::init (Graphic3d_TypeOfPrimitiveArray theType,
93                                         Standard_Integer theMaxVertexs,
94                                         Standard_Integer theMaxBounds,
95                                         Standard_Integer theMaxEdges,
96                                         Graphic3d_ArrayFlags theArrayOptions)
97 {
98   myType = theType;
99   myNormData = NULL;
100   myTexData  = NULL;
101   myColData  = NULL;
102   myAttribs.Nullify();
103   myIndices.Nullify();
104   myBounds.Nullify();
105
106   Handle(NCollection_AlignedAllocator) anAlloc = new NCollection_AlignedAllocator (16);
107   if ((theArrayOptions & Graphic3d_ArrayFlags_AttribsMutable) != 0
108    || (theArrayOptions & Graphic3d_ArrayFlags_AttribsDeinterleaved) != 0)
109   {
110     Graphic3d_AttribBuffer* anAttribs = new Graphic3d_AttribBuffer (anAlloc);
111     anAttribs->SetMutable     ((theArrayOptions & Graphic3d_ArrayFlags_AttribsMutable) != 0);
112     anAttribs->SetInterleaved ((theArrayOptions & Graphic3d_ArrayFlags_AttribsDeinterleaved) == 0);
113     myAttribs = anAttribs;
114   }
115   else
116   {
117     myAttribs = new Graphic3d_Buffer (anAlloc);
118   }
119   if (theMaxVertexs < 1)
120   {
121     return;
122   }
123
124   if (theMaxEdges > 0)
125   {
126     if ((theArrayOptions & Graphic3d_ArrayFlags_IndexesMutable) != 0)
127     {
128       myIndices = new Graphic3d_MutableIndexBuffer (anAlloc);
129     }
130     else
131     {
132       myIndices = new Graphic3d_IndexBuffer (anAlloc);
133     }
134     if (theMaxVertexs < Standard_Integer(USHRT_MAX))
135     {
136       if (!myIndices->Init<unsigned short> (theMaxEdges))
137       {
138         myIndices.Nullify();
139         return;
140       }
141     }
142     else
143     {
144       if (!myIndices->Init<unsigned int> (theMaxEdges))
145       {
146         myIndices.Nullify();
147         return;
148       }
149     }
150     myIndices->NbElements = 0;
151   }
152
153   Graphic3d_Attribute anAttribs[4];
154   Standard_Integer    aNbAttribs = 0;
155   anAttribs[aNbAttribs].Id       = Graphic3d_TOA_POS;
156   anAttribs[aNbAttribs].DataType = Graphic3d_TOD_VEC3;
157   ++aNbAttribs;
158   if ((theArrayOptions & Graphic3d_ArrayFlags_VertexNormal) != 0)
159   {
160     anAttribs[aNbAttribs].Id       = Graphic3d_TOA_NORM;
161     anAttribs[aNbAttribs].DataType = Graphic3d_TOD_VEC3;
162     ++aNbAttribs;
163   }
164   if ((theArrayOptions & Graphic3d_ArrayFlags_VertexTexel) != 0)
165   {
166     anAttribs[aNbAttribs].Id       = Graphic3d_TOA_UV;
167     anAttribs[aNbAttribs].DataType = Graphic3d_TOD_VEC2;
168     ++aNbAttribs;
169   }
170   if ((theArrayOptions & Graphic3d_ArrayFlags_VertexColor) != 0)
171   {
172     anAttribs[aNbAttribs].Id       = Graphic3d_TOA_COLOR;
173     anAttribs[aNbAttribs].DataType = Graphic3d_TOD_VEC4UB;
174     ++aNbAttribs;
175   }
176
177   if (!myAttribs->Init (theMaxVertexs, anAttribs, aNbAttribs))
178   {
179     myAttribs.Nullify();
180     myIndices.Nullify();
181     return;
182   }
183
184   Standard_Integer anAttribDummy = 0;
185   myAttribs->ChangeAttributeData (Graphic3d_TOA_POS, anAttribDummy, myPosStride);
186   myNormData = myAttribs->ChangeAttributeData (Graphic3d_TOA_NORM,  anAttribDummy, myNormStride);
187   myTexData  = myAttribs->ChangeAttributeData (Graphic3d_TOA_UV,    anAttribDummy, myTexStride);
188   myColData  = myAttribs->ChangeAttributeData (Graphic3d_TOA_COLOR, anAttribDummy, myColStride);
189
190   memset (myAttribs->ChangeData(), 0, size_t(myAttribs->Stride) * size_t(myAttribs->NbMaxElements()));
191   if ((theArrayOptions & Graphic3d_ArrayFlags_AttribsMutable) == 0
192    && (theArrayOptions & Graphic3d_ArrayFlags_AttribsDeinterleaved) == 0)
193   {
194     myAttribs->NbElements = 0;
195   }
196
197   if (theMaxBounds > 0)
198   {
199     myBounds = new Graphic3d_BoundBuffer (anAlloc);
200     if (!myBounds->Init (theMaxBounds, (theArrayOptions & Graphic3d_ArrayFlags_BoundColor) != 0))
201     {
202       myAttribs.Nullify();
203       myIndices.Nullify();
204       myBounds .Nullify();
205       return;
206     }
207     myBounds->NbBounds = 0;
208   }
209 }
210
211 // =======================================================================
212 // function : ~Graphic3d_ArrayOfPrimitives
213 // purpose  :
214 // =======================================================================
215 Graphic3d_ArrayOfPrimitives::~Graphic3d_ArrayOfPrimitives()
216 {
217   myIndices.Nullify();
218   myAttribs.Nullify();
219   myBounds .Nullify();
220 }
221
222 // =======================================================================
223 // function : AddBound
224 // purpose  :
225 // =======================================================================
226 Standard_Integer Graphic3d_ArrayOfPrimitives::AddBound (const Standard_Integer theEdgeNumber)
227 {
228   Standard_OutOfRange_Raise_if (myBounds.IsNull() || myBounds->NbBounds >= myBounds->NbMaxBounds, "TOO many BOUND");
229   myBounds->Bounds[myBounds->NbBounds] = theEdgeNumber;
230   return ++myBounds->NbBounds;
231 }
232
233 // =======================================================================
234 // function : AddBound
235 // purpose  :
236 // =======================================================================
237 Standard_Integer Graphic3d_ArrayOfPrimitives::AddBound (const Standard_Integer theEdgeNumber,
238                                                         const Standard_Real    theR,
239                                                         const Standard_Real    theG,
240                                                         const Standard_Real    theB)
241 {
242   Standard_OutOfRange_Raise_if (myBounds.IsNull() || myBounds->NbBounds >= myBounds->NbMaxBounds, "TOO many BOUND");
243   myBounds->Bounds[myBounds->NbBounds] = theEdgeNumber;
244   ++myBounds->NbBounds;
245   SetBoundColor (myBounds->NbBounds, theR, theG, theB);
246   return myBounds->NbBounds;
247 }
248
249 // =======================================================================
250 // function : AddEdge
251 // purpose  :
252 // =======================================================================
253 Standard_Integer Graphic3d_ArrayOfPrimitives::AddEdge (const Standard_Integer theVertexIndex)
254 {
255   Standard_OutOfRange_Raise_if (myIndices.IsNull() || myIndices->NbElements >= myIndices->NbMaxElements(), "TOO many EDGE");
256   Standard_OutOfRange_Raise_if (theVertexIndex < 1 || theVertexIndex > myAttribs->NbElements, "BAD VERTEX index");
257   const Standard_Integer aVertIndex = theVertexIndex - 1;
258   myIndices->SetIndex (myIndices->NbElements, aVertIndex);
259   return ++myIndices->NbElements;
260 }
261
262 // =======================================================================
263 // function : StringType
264 // purpose  :
265 // =======================================================================
266 Standard_CString Graphic3d_ArrayOfPrimitives::StringType() const
267 {
268   switch (myType)
269   {
270     case Graphic3d_TOPA_POINTS:           return "ArrayOfPoints";
271     case Graphic3d_TOPA_SEGMENTS:         return "ArrayOfSegments";
272     case Graphic3d_TOPA_POLYLINES:        return "ArrayOfPolylines";
273     case Graphic3d_TOPA_TRIANGLES:        return "ArrayOfTriangles";
274     case Graphic3d_TOPA_TRIANGLESTRIPS:   return "ArrayOfTriangleStrips";
275     case Graphic3d_TOPA_TRIANGLEFANS:     return "ArrayOfTriangleFans";
276     case Graphic3d_TOPA_LINES_ADJACENCY:          return "ArrayOfLinesAdjacency";
277     case Graphic3d_TOPA_LINE_STRIP_ADJACENCY:     return "ArrayOfLineStripAdjacency";
278     case Graphic3d_TOPA_TRIANGLES_ADJACENCY:      return "ArrayOfTrianglesAdjacency";
279     case Graphic3d_TOPA_TRIANGLE_STRIP_ADJACENCY: return "ArrayOfTriangleStripAdjacency";
280     case Graphic3d_TOPA_QUADRANGLES:      return "ArrayOfQuadrangles";
281     case Graphic3d_TOPA_QUADRANGLESTRIPS: return "ArrayOfQuadrangleStrips";
282     case Graphic3d_TOPA_POLYGONS:         return "ArrayOfPolygons";
283     case Graphic3d_TOPA_UNDEFINED:        return "UndefinedArray";
284   }
285   return "UndefinedArray";
286 }
287
288 // =======================================================================
289 // function : ItemNumber
290 // purpose  :
291 // =======================================================================
292 Standard_Integer Graphic3d_ArrayOfPrimitives::ItemNumber() const
293 {
294   if (myAttribs.IsNull())
295   {
296     return -1;
297   }
298
299   switch (myType)
300   {
301     case Graphic3d_TOPA_POINTS:           return myAttribs->NbElements;
302     case Graphic3d_TOPA_POLYLINES:
303     case Graphic3d_TOPA_POLYGONS:         return !myBounds.IsNull() ? myBounds->NbBounds : 1;
304     case Graphic3d_TOPA_SEGMENTS:         return myIndices.IsNull() || myIndices->NbElements < 1
305                                                ? myAttribs->NbElements / 2
306                                                : myIndices->NbElements / 2;
307     case Graphic3d_TOPA_TRIANGLES:        return myIndices.IsNull() || myIndices->NbElements < 1
308                                                ? myAttribs->NbElements / 3
309                                                : myIndices->NbElements / 3;
310     case Graphic3d_TOPA_QUADRANGLES:      return myIndices.IsNull() || myIndices->NbElements < 1
311                                                ? myAttribs->NbElements / 4
312                                                : myIndices->NbElements / 4;
313     case Graphic3d_TOPA_TRIANGLESTRIPS:   return !myBounds.IsNull()
314                                                ? myAttribs->NbElements - 2 * myBounds->NbBounds
315                                                : myAttribs->NbElements - 2;
316     case Graphic3d_TOPA_QUADRANGLESTRIPS: return !myBounds.IsNull()
317                                                ? myAttribs->NbElements / 2 - myBounds->NbBounds
318                                                : myAttribs->NbElements / 2 - 1;
319     case Graphic3d_TOPA_TRIANGLEFANS:     return !myBounds.IsNull()
320                                                ? myAttribs->NbElements - 2 * myBounds->NbBounds
321                                                : myAttribs->NbElements - 2;
322     case Graphic3d_TOPA_LINES_ADJACENCY:  return myIndices.IsNull() || myIndices->NbElements < 1
323                                                ? myAttribs->NbElements / 4
324                                                : myIndices->NbElements / 4;
325     case Graphic3d_TOPA_LINE_STRIP_ADJACENCY: return !myBounds.IsNull()
326                                                     ? myAttribs->NbElements - 4 * myBounds->NbBounds
327                                                     : myAttribs->NbElements - 4;
328     case Graphic3d_TOPA_TRIANGLES_ADJACENCY: return myIndices.IsNull() || myIndices->NbElements < 1
329                                                   ? myAttribs->NbElements / 6
330                                                   : myIndices->NbElements / 6;
331     case Graphic3d_TOPA_TRIANGLE_STRIP_ADJACENCY: return !myBounds.IsNull()
332                                                 ? myAttribs->NbElements - 4 * myBounds->NbBounds
333                                                 : myAttribs->NbElements - 4;
334     case Graphic3d_TOPA_UNDEFINED:        return -1;
335   }
336   return -1;
337 }
338
339 // =======================================================================
340 // function : IsValid
341 // purpose  :
342 // =======================================================================
343 Standard_Boolean Graphic3d_ArrayOfPrimitives::IsValid()
344 {
345   if (myAttribs.IsNull())
346   {
347     return Standard_False;
348   }
349
350   Standard_Integer nvertexs = myAttribs->NbElements;
351   Standard_Integer nbounds  = myBounds.IsNull()  ? 0 : myBounds->NbBounds;
352   Standard_Integer nedges   = myIndices.IsNull() ? 0 : myIndices->NbElements;
353   switch (myType)
354   {
355     case Graphic3d_TOPA_POINTS:
356       if (nvertexs < 1)
357       {
358         return Standard_False;
359       }
360       break;
361     case Graphic3d_TOPA_POLYLINES:
362       if (nedges > 0
363        && nedges < 2)
364       {
365         return Standard_False;
366       }
367       if (nvertexs < 2)
368       {
369         return Standard_False;
370       }
371       break;
372     case Graphic3d_TOPA_SEGMENTS:
373       if (nvertexs < 2)
374       {
375         return Standard_False;
376       }
377       break;
378     case Graphic3d_TOPA_POLYGONS:
379       if (nedges > 0
380        && nedges < 3)
381       {
382         return Standard_False;
383       }
384       if (nvertexs < 3)
385       {
386         return Standard_False;
387       }
388       break;
389     case Graphic3d_TOPA_TRIANGLES:
390       if (nedges > 0)
391       {
392         if (nedges < 3
393          || nedges % 3 != 0)
394         {
395           if (nedges <= 3)
396           {
397             return Standard_False;
398           }
399           myIndices->NbElements = 3 * (nedges / 3);
400         }
401       }
402       else if (nvertexs < 3
403             || nvertexs % 3 != 0 )
404       {
405         if (nvertexs <= 3)
406         {
407           return Standard_False;
408         }
409         myAttribs->NbElements = 3 * (nvertexs / 3);
410       }
411       break;
412     case Graphic3d_TOPA_QUADRANGLES:
413       if (nedges > 0)
414       {
415         if (nedges < 4
416          || nedges % 4 != 0)
417         {
418           if (nedges <= 4)
419           {
420             return Standard_False;
421           }
422           myIndices->NbElements = 4 * (nedges / 4);
423         }
424       }
425       else if (nvertexs < 4
426             || nvertexs % 4 != 0)
427       {
428         if (nvertexs <= 4)
429         {
430           return Standard_False;
431         }
432         myAttribs->NbElements = 4 * (nvertexs / 4);
433       }
434       break;
435     case Graphic3d_TOPA_TRIANGLEFANS:
436     case Graphic3d_TOPA_TRIANGLESTRIPS:
437       if (nvertexs < 3)
438       {
439         return Standard_False;
440       }
441       break;
442     case Graphic3d_TOPA_QUADRANGLESTRIPS:
443       if (nvertexs < 4)
444       {
445         return Standard_False;
446       }
447       break;
448     case Graphic3d_TOPA_LINES_ADJACENCY:
449     case Graphic3d_TOPA_LINE_STRIP_ADJACENCY:
450       if (nvertexs < 4)
451       {
452         return Standard_False;
453       }
454       break;
455     case Graphic3d_TOPA_TRIANGLES_ADJACENCY:
456     case Graphic3d_TOPA_TRIANGLE_STRIP_ADJACENCY:
457       if (nvertexs < 6)
458       {
459         return Standard_False;
460       }
461       break;
462     case Graphic3d_TOPA_UNDEFINED:
463     default:
464       return Standard_False;
465   }
466
467   // total number of edges(vertices) in bounds should be the same as variable
468   // of total number of defined edges(vertices); if no edges - only vertices
469   // could be in bounds.
470   if (nbounds > 0)
471   {
472     Standard_Integer n = 0;
473     for (Standard_Integer aBoundIter = 0; aBoundIter < nbounds; ++aBoundIter)
474     {
475       n += myBounds->Bounds[aBoundIter];
476     }
477     if (nedges > 0
478      && n != nedges)
479     {
480       if (nedges <= n)
481       {
482         return Standard_False;
483       }
484       myIndices->NbElements = n;
485     }
486     else if (nedges == 0
487           && n != nvertexs)
488     {
489       if (nvertexs <= n)
490       {
491         return Standard_False;
492       }
493       myAttribs->NbElements = n;
494     }
495   }
496
497   // check that edges (indexes to an array of vertices) are in range.
498   if (nedges > 0)
499   {
500     for (Standard_Integer anEdgeIter = 0; anEdgeIter < nedges; ++anEdgeIter)
501     {
502       if (myIndices->Index (anEdgeIter) >= myAttribs->NbElements)
503       {
504         return Standard_False;
505       }
506     }
507   }
508   return Standard_True;
509 }