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