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