Integration of OCCT 6.5.0 from SVN
[occt.git] / src / VrmlData / VrmlData_ShapeConvert.cxx
CommitLineData
7fd59977 1// File: VrmlData_ShapeConvert.cxx
2// Created: 04.08.07 10:09
3// Author: Alexander GRIGORIEV
4// Copyright: Open Cascade 2007
5
6
7#include <VrmlData_ShapeConvert.hxx>
8#include <VrmlData_Scene.hxx>
9#include <VrmlData_Group.hxx>
10#include <VrmlData_Coordinate.hxx>
11#include <VrmlData_IndexedFaceSet.hxx>
12#include <VrmlData_IndexedLineSet.hxx>
13#include <VrmlData_ShapeNode.hxx>
14#include <BRepMesh_IncrementalMesh.hxx>
15#include <BRep_Builder.hxx>
16#include <BRep_Tool.hxx>
17#include <Geom_Surface.hxx>
18#include <NCollection_DataMap.hxx>
19#include <Poly_Triangulation.hxx>
20#include <Poly_Connect.hxx>
21#include <Poly_PolygonOnTriangulation.hxx>
22#include <Poly_Polygon3D.hxx>
23#include <Precision.hxx>
24#include <TColgp_Array1OfPnt2d.hxx>
25#include <TopExp_Explorer.hxx>
26#include <TopoDS.hxx>
27#include <TopoDS_Edge.hxx>
28#include <TopoDS_Face.hxx>
29#include <TopoDS_Shape.hxx>
30#include <TopoDS_Wire.hxx>
31#include <GCPnts_TangentialDeflection.hxx>
32#include <BRepAdaptor_Curve.hxx>
33#include <TColStd_Array1OfReal.hxx>
34#include <TColStd_HArray1OfReal.hxx>
35#include <TShort_Array1OfShortReal.hxx>
36#include <GeomLib.hxx>
37#include <TShort_HArray1OfShortReal.hxx>
38
39//=======================================================================
40//function : IsEqual
41//purpose : for NCollection_DataMap interface
42//=======================================================================
43
44inline Standard_Boolean IsEqual (const TopoDS_Shape& one,
45 const TopoDS_Shape& two)
46{
47 return one == two;
48}
49
50//=======================================================================
51//function : AddShape
52//purpose :
53//=======================================================================
54
55void VrmlData_ShapeConvert::AddShape (const TopoDS_Shape& theShape,
56 const char * theName)
57{
58 ShapeData aData;/* = { - compilation problem on SUN
59 TCollection_AsciiString(),
60 theShape,
61 NULL
62 };*/
63 aData.Shape = theShape;
64 aData.Node = NULL;
65
66 if (theName) {
67 char buf[2048], * optr = &buf[0];
68 char * eptr = &buf[sizeof(buf)-1];
69 for (const char * ptr = theName;; ptr++) {
70 int sym = *ptr;
71 if (sym == '\0' || sym == '\n' || sym == '\r') {
72 * optr = '\0';
73 break;
74 }
75 if (sym == '\"' || sym == '\\')
76 * optr = '/';
77 else if (sym == '.')
78 * optr = '_';
79 else
80 * optr = sym;
81 if (++optr >= eptr) {
82 *optr = '\0';
83 break;
84 }
85 }
86 aData.Name = buf;
87 }
88 myShapes.Append (aData);
89}
90
91//=======================================================================
92//function : Convert
93//purpose :
94//=======================================================================
95
96void VrmlData_ShapeConvert::Convert (const Standard_Boolean theExtractFaces,
97 const Standard_Boolean theExtractEdges,
98 const Standard_Real theDeflection,
99 const Standard_Real theDeflAngle)
100{
101 const Standard_Real aDeflection =
102 theDeflection < 0.0001 ? 0.0001 : theDeflection;
103
104 Standard_Boolean Extract[2] = {theExtractFaces, theExtractEdges};
105 TopAbs_ShapeEnum ShapeType[2] = {TopAbs_FACE, TopAbs_EDGE};
106 Standard_Integer i;
107
108 const Handle(NCollection_IncAllocator) anAlloc = new NCollection_IncAllocator;
109
110 // Relocation map for converted shapes. We should distinguish both TShape
111 // and Orientation in this map.
112 NCollection_DataMap <TopoDS_Shape,Handle(VrmlData_Geometry)>
113 aRelMap (100, anAlloc);
114
115
116 NCollection_List<ShapeData>::Iterator anIter (myShapes);
117 for (; anIter.More(); anIter.Next()) {
118
119 ShapeData& aData = anIter.ChangeValue();
120 Handle(VrmlData_Group) aGroup =
121 new VrmlData_Group (myScene, aData.Name.ToCString());
122 myScene.AddNode (aGroup);
123
124 for(i = 0; i < 2; ++i) {
125
126 if(!Extract[i]) continue;
127
128 TopExp_Explorer anExp (aData.Shape, ShapeType[i]);
129 for (; anExp.More(); anExp.Next()) {
130 const TopoDS_Shape& aShape = anExp.Current();
131 TopLoc_Location aLoc;
132 Handle(VrmlData_Geometry) aTShapeNode;
133 const Standard_Boolean isReverse=(aShape.Orientation()==TopAbs_REVERSED);
134
135 TopoDS_Shape aTestedShape;
136 aTestedShape.TShape (aShape.TShape());
137 aTestedShape.Orientation (isReverse ? TopAbs_REVERSED : TopAbs_FORWARD);
138 Standard_Boolean isTessellate (Standard_False);
139 switch (ShapeType[i]) {
140 case TopAbs_FACE:
141 {
142 const TopoDS_Face& aFace = TopoDS::Face (aShape);
143 if (aFace.IsNull() == Standard_False) {
144 Handle(Poly_Triangulation) aTri =
145 BRep_Tool::Triangulation (aFace, aLoc);
146
147 if (aRelMap.IsBound (aTestedShape)) {
148 aTShapeNode = aRelMap(aTestedShape);
149 break;
150 }
151
152 if (aTri.IsNull())
153 isTessellate = Standard_True;
154 // Check the existing deflection
155 else if (aTri->Deflection() > aDeflection+ Precision::Confusion())
156 isTessellate = Standard_True;
157 if (isTessellate) {
158 // Triangulate the face by the standard OCC mesher
159 BRepMesh_IncrementalMesh IM (aFace, aDeflection, Standard_False, theDeflAngle);
160 aTri = BRep_Tool::Triangulation (aFace, aLoc);
161 }
162 if (aTri.IsNull() == Standard_False) {
163 TopoDS_Shape aTestedShapeRev = aTestedShape;
164 aTestedShapeRev.Orientation (isReverse ?
165 TopAbs_FORWARD : TopAbs_REVERSED);
166 Handle(VrmlData_IndexedFaceSet) aFaceSetToReuse;
167 if (aRelMap.IsBound (aTestedShapeRev))
168 aFaceSetToReuse = Handle(VrmlData_IndexedFaceSet)::DownCast
169 (aRelMap(aTestedShapeRev));
170
171 Handle(VrmlData_Coordinate) aCoordToReuse;
172 if (aFaceSetToReuse.IsNull() == Standard_False)
173 aCoordToReuse = aFaceSetToReuse->Coordinates();
174
175 aTShapeNode = triToIndexedFaceSet (aTri, aFace, aCoordToReuse);
176 myScene.AddNode (aTShapeNode, Standard_False);
177 // Bind the converted face
178 aRelMap.Bind (aTestedShape, aTShapeNode);
179 }
180 }
181 }
182 break;
183 case TopAbs_WIRE:
184 {
185 const TopoDS_Wire& aWire = TopoDS::Wire (aShape);
186 if (aWire.IsNull() == Standard_False) {
187 }
188 }
189 break;
190 case TopAbs_EDGE:
191 {
192 const TopoDS_Edge& aEdge = TopoDS::Edge (aShape);
193 if (aEdge.IsNull() == Standard_False) {
194 Handle(Poly_Polygon3D) aPol = BRep_Tool::Polygon3D (aEdge, aLoc);
195
196 if (aRelMap.IsBound (aTestedShape)) {
197 aTShapeNode = aRelMap(aTestedShape);
198 break;
199 }
200 // Check the presence of reversly oriented Edge. It can also be used
201 // because we do not distinguish the orientation for edges.
202 aTestedShape.Orientation (isReverse ?
203 TopAbs_FORWARD : TopAbs_REVERSED);
204 if (aRelMap.IsBound (aTestedShape)) {
205 aTShapeNode = aRelMap(aTestedShape);
206 break;
207 }
208
209 if (aPol.IsNull())
210 isTessellate = Standard_True;
211 // Check the existing deflection
212 else if (aPol->Deflection() > aDeflection+ Precision::Confusion()
213 && BRep_Tool::IsGeometric(aEdge))
214 isTessellate = Standard_True;
215
216 if (isTessellate && BRep_Tool::IsGeometric(aEdge)) {
217 //try to find PolygonOnTriangulation
218 Handle(Poly_PolygonOnTriangulation) aPT;
219 Handle(Poly_Triangulation) aT;
220 TopLoc_Location aL;
221
222 Standard_Boolean found = Standard_False;
223 for(i = 1; Standard_True; i++) {
224
225 BRep_Tool::PolygonOnTriangulation(aEdge, aPT, aT, aL, i);
226
227 if(aPT.IsNull() || aT.IsNull()) break;
228
229 if(aPT->Deflection() <= aDeflection + Precision::Confusion() &&
230 aPT->HasParameters()) {
231 found = Standard_True;
232 break;
233 }
234
235 }
236
237 if(found) {
238
239 BRepAdaptor_Curve aCurve(aEdge);
240 Handle(TColStd_HArray1OfReal) aPrs = aPT->Parameters();
241 Standard_Integer nbNodes = aPT->NbNodes();
242 TColgp_Array1OfPnt arrNodes(1, nbNodes);
243 TColStd_Array1OfReal arrUVNodes(1, nbNodes);
244
245 for(i = 1; i <= nbNodes; i++) {
246 arrUVNodes(i) = aPrs->Value(aPrs->Lower() + i - 1);
247 arrNodes(i) = aCurve.Value(arrUVNodes(i));
248 }
249 aPol = new Poly_Polygon3D(arrNodes, arrUVNodes);
250 aPol->Deflection (aPT->Deflection());
251 }
252 else{
253
254 BRepAdaptor_Curve aCurve(aEdge);
255 const Standard_Real aFirst = aCurve.FirstParameter();
256 const Standard_Real aLast = aCurve.LastParameter();
257
258 GCPnts_TangentialDeflection TD (aCurve, aFirst, aLast,
259 theDeflAngle, aDeflection, 2);
260 const Standard_Integer nbNodes = TD.NbPoints();
261
262 TColgp_Array1OfPnt arrNodes(1, nbNodes);
263 TColStd_Array1OfReal arrUVNodes(1, nbNodes);
264 for (i = 1; i <= nbNodes; i++) {
265 arrNodes(i) = TD.Value(i);
266 arrUVNodes(i) = TD.Parameter(i);
267 }
268 aPol = new Poly_Polygon3D(arrNodes, arrUVNodes);
269 aPol->Deflection (aDeflection);
270 }
271
272 BRep_Builder aBld;
273 aBld.UpdateEdge (aEdge, aPol);
274 }
275 aTShapeNode = polToIndexedLineSet (aPol);
276 myScene.AddNode (aTShapeNode, Standard_False);
277 // Bind the converted face
278 aRelMap.Bind (aTestedShape, aTShapeNode);
279 }
280 }
281 break;
282 }
283
284 if (aTShapeNode.IsNull() == Standard_False) {
285 const Handle(VrmlData_ShapeNode) aShapeNode =
286 new VrmlData_ShapeNode (myScene, 0L);
287 aShapeNode->SetAppearance (ShapeType[i] == TopAbs_FACE ?
288 defaultMaterialFace():defaultMaterialEdge());
289 myScene.AddNode (aShapeNode, Standard_False);
290 aShapeNode->SetGeometry (aTShapeNode);
291 if (aLoc.IsIdentity())
292 // Store the shape node directly into the main Group.
293 aGroup->AddNode (aShapeNode);
294 else {
295 // Create a Transform grouping node
296 Handle(VrmlData_Group) aTrans = new VrmlData_Group (myScene, 0L,
297 Standard_True);
298 gp_Trsf aTrsf (aLoc);
299 if (fabs(myScale - 1.) > Precision::Confusion()) {
300 const gp_XYZ aTransl = aTrsf.TranslationPart() * myScale;
301 aTrsf.SetTranslationPart (aTransl);
302 }
303 aTrans->SetTransform (aTrsf);
304 myScene.AddNode (aTrans, Standard_False);
305 aGroup->AddNode (aTrans);
306
307 // Store the shape node under the transform.
308 aTrans->AddNode (aShapeNode);
309 }
310 }
311 }
312 }
313 }
314 myShapes.Clear();
315}
316
317//=======================================================================
318//function : triToIndexedFaceSet
319//purpose :
320//=======================================================================
321
322Handle_VrmlData_Geometry VrmlData_ShapeConvert::triToIndexedFaceSet
323 (const Handle_Poly_Triangulation& theTri,
324 const TopoDS_Face& theFace,
325 const Handle_VrmlData_Coordinate& theCoord)
326{
327 Standard_Integer i;
328 const Standard_Integer nNodes (theTri->NbNodes());
329 const Standard_Integer nTriangles (theTri->NbTriangles());
330 const TColgp_Array1OfPnt& arrPolyNodes = theTri->Nodes();
331 const Poly_Array1OfTriangle& arrTriangles = theTri->Triangles();
332
333 const Handle(VrmlData_IndexedFaceSet) aFaceSet =
334 new VrmlData_IndexedFaceSet (myScene,
335 0L, // no name
336 Standard_True, // IsCCW
337 Standard_False, // IsSolid
338 Standard_False); // IsConvex
339 const Handle(NCollection_IncAllocator)& anAlloc = myScene.Allocator();
340 const Standard_Boolean isReverse = (theFace.Orientation() == TopAbs_REVERSED);
341
342 // Create the array of triangles
343 const Standard_Integer ** arrPolygons = static_cast<const Standard_Integer **>
344 (anAlloc->Allocate (nTriangles * sizeof(const Standard_Integer *)));
345 aFaceSet->SetPolygons (nTriangles, arrPolygons);
346
347 // Store the triangles
348 for (i = 0; i < nTriangles; i++) {
349 Standard_Integer * aPolygon = static_cast<Standard_Integer *>
350 (anAlloc->Allocate (4*sizeof(Standard_Integer)));
351 aPolygon[0] = 3;
352 arrTriangles(i+1).Get (aPolygon[1],aPolygon[2],aPolygon[3]);
353 aPolygon[1]--;
354 if (isReverse) {
355 const Standard_Integer aTmp = aPolygon[2]-1;
356 aPolygon[2] = aPolygon[3]-1;
357 aPolygon[3] = aTmp;
358 } else {
359 aPolygon[2]--;
360 aPolygon[3]--;
361 }
362 arrPolygons[i] = aPolygon;
363 }
364
365 // Create the Coordinates node
366 if (theCoord.IsNull() == Standard_False)
367 aFaceSet->SetCoordinates (theCoord);
368 else {
369 gp_XYZ * arrNodes = static_cast <gp_XYZ *>
370 (anAlloc->Allocate (nNodes * sizeof(gp_XYZ)));
371 for (i = 0; i < nNodes; i++)
372 arrNodes[i] = arrPolyNodes(i+1).XYZ() * myScale;
373
374 const Handle(VrmlData_Coordinate) aCoordNode =
375 new VrmlData_Coordinate (myScene, 0L, nNodes, arrNodes);
376 myScene.AddNode (aCoordNode, Standard_False);
377 aFaceSet->SetCoordinates (aCoordNode);
378 }
379
380 // Create the Normals node if theTri has normals
381 if(theTri->HasNormals()) {
382 gp_XYZ * arrVec = static_cast <gp_XYZ *>
383 (anAlloc->Allocate (nNodes * sizeof(gp_XYZ)));
384 const TShort_Array1OfShortReal& Norm = theTri->Normals();
385 Standard_Integer j;
386 for (i = 0, j = 1; i < nNodes; i++, j += 3) {
387
388 gp_XYZ aNormal(Norm(j), Norm(j+1), Norm(j+2));
389 arrVec[i] = aNormal;
390
391 }
392 const Handle(VrmlData_Normal) aNormalNode =
393 new VrmlData_Normal (myScene, 0L, nNodes, arrVec);
394 myScene.AddNode (aNormalNode, Standard_False);
395 aFaceSet->SetNormals (aNormalNode);
396 return aFaceSet;
397 }
398
399 Poly_Connect PC(theTri);
400 // Create the Normals node (if UV- values are available)
401 TopLoc_Location aLoc;
402 const Standard_Real aConf2 = Precision::Confusion()*Precision::Confusion();
403 const Handle(Geom_Surface) aSurface = BRep_Tool::Surface (theFace, aLoc);
404 if (theTri->HasUVNodes() && aSurface.IsNull() == Standard_False) {
405 if (aSurface->IsCNu(1) && aSurface->IsCNv(1))
406 {
407 Standard_Integer nbNormVal = nNodes * 3;
408 Handle(TShort_HArray1OfShortReal) Normals =
409 new TShort_HArray1OfShortReal(1, nbNormVal);
410
411 const TColgp_Array1OfPnt2d& arrUV = theTri->UVNodes();
412 gp_XYZ * arrVec = static_cast <gp_XYZ *>
413 (anAlloc->Allocate (nNodes * sizeof(gp_XYZ)));
414
415 // Compute the normal vectors
416 Standard_Real Tol = Sqrt(aConf2);
417 for (i = 0; i < nNodes; i++) {
418 const gp_Pnt2d& aUV = arrUV(i+1);
419
420 gp_Dir aNormal;
421
422 if (GeomLib::NormEstim(aSurface, aUV, Tol, aNormal) > 1) {
423 //Try to estimate as middle normal of adjacent triangles
424 Standard_Integer n[3];
425
426 gp_XYZ eqPlan(0., 0., 0.);
427 for (PC.Initialize(i+1); PC.More(); PC.Next()) {
428 arrTriangles(PC.Value()).Get(n[0], n[1], n[2]);
429 gp_XYZ v1(arrPolyNodes(n[1]).Coord()-arrPolyNodes(n[0]).Coord());
430 gp_XYZ v2(arrPolyNodes(n[2]).Coord()-arrPolyNodes(n[1]).Coord());
431 gp_XYZ vv = v1^v2;
432
433 Standard_Real mod = vv.Modulus();
434 if (mod < Tol)
435 continue;
436
437 eqPlan += vv/mod;
438 }
439
440 if (eqPlan.SquareModulus() > gp::Resolution())
441 aNormal = gp_Dir(eqPlan);
442 }
443 if (isReverse)
444 aNormal.Reverse();
445
446 if (aNormal.X()*aNormal.X() < aConf2)
447 aNormal.SetX(0.);
448 if (aNormal.Y()*aNormal.Y() < aConf2)
449 aNormal.SetY(0.);
450 if (aNormal.Z()*aNormal.Z() < aConf2)
451 aNormal.SetZ(0.);
452 arrVec[i] = aNormal.XYZ();
453
454 Standard_Integer j = i * 3;
455 Normals->SetValue(j + 1, aNormal.X());
456 Normals->SetValue(j + 2, aNormal.Y());
457 Normals->SetValue(j + 3, aNormal.Z());
458
459 }
460
461 theTri->SetNormals(Normals);
462
463 const Handle(VrmlData_Normal) aNormalNode =
464 new VrmlData_Normal (myScene, 0L, nNodes, arrVec);
465 myScene.AddNode (aNormalNode, Standard_False);
466 aFaceSet->SetNormals (aNormalNode);
467 }
468 }
469
470 return aFaceSet;
471}
472
473//=======================================================================
474//function : polToIndexedLineSet
475//purpose : single polygon3D => IndexedLineSet
476//=======================================================================
477
478Handle_VrmlData_Geometry VrmlData_ShapeConvert::polToIndexedLineSet
479 (const Handle_Poly_Polygon3D& thePol)
480{
481 Standard_Integer i;
482 const Standard_Integer nNodes (thePol->NbNodes());
483 const TColgp_Array1OfPnt& arrPolyNodes = thePol->Nodes();
484 const Handle(NCollection_IncAllocator)& anAlloc = myScene.Allocator();
485
486 const Handle(VrmlData_IndexedLineSet) aLineSet =
487 new VrmlData_IndexedLineSet (myScene, 0L);
488
489 // Create the array of polygons (1 member)
490 const Standard_Integer ** arrPolygons = static_cast<const Standard_Integer **>
491 (anAlloc->Allocate (sizeof(const Standard_Integer *)));
492 aLineSet->SetPolygons (1, arrPolygons);
493
494 // Store the polygon
495 Standard_Integer * aPolygon = static_cast<Standard_Integer *>
496 (anAlloc->Allocate ((nNodes+1)*sizeof(Standard_Integer)));
497 aPolygon[0] = nNodes;
498 for (i = 1; i <= nNodes; i++)
499 aPolygon[i] = i-1;
500 arrPolygons[0] = aPolygon;
501
502 // Create the Coordinates node
503 gp_XYZ * arrNodes = static_cast <gp_XYZ *>
504 (anAlloc->Allocate (nNodes * sizeof(gp_XYZ)));
505 for (i = 0; i < nNodes; i++)
506 arrNodes[i] = arrPolyNodes(i+1).XYZ() * myScale;
507
508 const Handle(VrmlData_Coordinate) aCoordNode =
509 new VrmlData_Coordinate (myScene, 0L, nNodes, arrNodes);
510 myScene.AddNode (aCoordNode, Standard_False);
511 aLineSet->SetCoordinates (aCoordNode);
512
513 return aLineSet;
514}
515
516//=======================================================================
517//function : defaultMaterialFace
518//purpose :
519//=======================================================================
520
521Handle(VrmlData_Appearance) VrmlData_ShapeConvert::defaultMaterialFace () const
522{
523 static char aNodeName[] = "__defaultMaterialFace";
524 Handle(VrmlData_Appearance) anAppearance =
525 Handle(VrmlData_Appearance)::DownCast(myScene.FindNode(aNodeName));
526 if (anAppearance.IsNull()) {
527 const Handle(VrmlData_Material) aMaterial =
528 new VrmlData_Material (myScene, 0L, 1.0, 0.022, 0.);
529 aMaterial->SetDiffuseColor (Quantity_Color(0.780392, 0.568627, 0.113725,
530 Quantity_TOC_RGB));
531 aMaterial->SetEmissiveColor(Quantity_Color(0.329412, 0.223529, 0.027451,
532 Quantity_TOC_RGB));
533 aMaterial->SetSpecularColor(Quantity_Color(0.992157, 0.941176, 0.807843,
534 Quantity_TOC_RGB));
535 myScene.AddNode (aMaterial, Standard_False);
536 anAppearance = new VrmlData_Appearance (myScene, aNodeName);
537 anAppearance->SetMaterial (aMaterial);
538 myScene.AddNode (anAppearance, Standard_False);
539 }
540 return anAppearance;
541}
542
543//=======================================================================
544//function : defaultMaterialEdge
545//purpose :
546//=======================================================================
547
548Handle(VrmlData_Appearance) VrmlData_ShapeConvert::defaultMaterialEdge () const
549{
550 static char aNodeName[] = "__defaultMaterialEdge";
551 Handle(VrmlData_Appearance) anAppearance =
552 Handle(VrmlData_Appearance)::DownCast(myScene.FindNode(aNodeName));
553 if (anAppearance.IsNull()) {
554 const Handle(VrmlData_Material) aMaterial =
555 new VrmlData_Material (myScene, 0L, 0.2, 0.2, 0.2);
556 aMaterial->SetDiffuseColor (Quantity_Color(0.2, 0.7, 0.2,
557 Quantity_TOC_RGB));
558 aMaterial->SetEmissiveColor(Quantity_Color(0.2, 0.7, 0.2,
559 Quantity_TOC_RGB));
560 aMaterial->SetSpecularColor(Quantity_Color(0.2, 0.7, 0.2,
561 Quantity_TOC_RGB));
562 myScene.AddNode (aMaterial, Standard_False);
563 anAppearance = new VrmlData_Appearance (myScene, aNodeName);
564 anAppearance->SetMaterial (aMaterial);
565 myScene.AddNode (anAppearance, Standard_False);
566 }
567 return anAppearance;
568}