973c2be1 |
1 | // Copyright (c) 1999-2014 OPEN CASCADE SAS |
b311480e |
2 | // |
973c2be1 |
3 | // This file is part of Open CASCADE Technology software library. |
b311480e |
4 | // |
d5f74e42 |
5 | // This library is free software; you can redistribute it and/or modify it under |
6 | // the terms of the GNU Lesser General Public License version 2.1 as published |
973c2be1 |
7 | // by the Free Software Foundation, with special exception defined in the file |
8 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT |
9 | // distribution for complete text of the license and disclaimer of any warranty. |
b311480e |
10 | // |
973c2be1 |
11 | // Alternatively, this file may be used under the terms of Open CASCADE |
12 | // commercial license or contractual agreement. |
b311480e |
13 | |
7fd59977 |
14 | #include <VrmlConverter_Drawer.hxx> |
15 | #include <VrmlConverter_ShadedShape.hxx> |
16 | #include <Vrml_Normal.hxx> |
17 | #include <TopoDS_Shape.hxx> |
18 | #include <TopoDS_Face.hxx> |
19 | #include <TopoDS.hxx> |
20 | #include <TopAbs.hxx> |
21 | #include <Poly_Connect.hxx> |
22 | #include <TColgp_Array1OfDir.hxx> |
23 | #include <TColgp_HArray1OfVec.hxx> |
24 | #include <Poly_Triangle.hxx> |
25 | #include <Poly_Triangulation.hxx> |
26 | #include <BRepTools.hxx> |
27 | #include <BRepMesh.hxx> |
28 | #include <BRep_Tool.hxx> |
29 | #include <gp_Pnt.hxx> |
30 | #include <gp_Vec.hxx> |
31 | #include <TopExp_Explorer.hxx> |
32 | #include <TopLoc_Location.hxx> |
33 | #include <TColgp_Array1OfPnt.hxx> |
34 | #include <Poly_Array1OfTriangle.hxx> |
35 | #include <Vrml_IndexedFaceSet.hxx> |
36 | #include <Vrml_Coordinate3.hxx> |
37 | #include <BRepBndLib.hxx> |
38 | #include <Bnd_Box.hxx> |
39 | #include <math.hxx> |
40 | #include <TColStd_HArray1OfInteger.hxx> |
41 | #include <Geom_Surface.hxx> |
42 | #include <CSLib_DerivativeStatus.hxx> |
43 | #include <CSLib_NormalStatus.hxx> |
44 | #include <CSLib.hxx> |
45 | #include <BRepAdaptor_Surface.hxx> |
46 | #include <TColgp_Array1OfPnt2d.hxx> |
47 | #include <Precision.hxx> |
48 | #include <Vrml_Material.hxx> |
49 | #include <VrmlConverter_ShadingAspect.hxx> |
50 | #include <Vrml_ShapeHints.hxx> |
51 | #include <Vrml_MaterialBindingAndNormalBinding.hxx> |
52 | #include <Vrml_NormalBinding.hxx> |
53 | #include <Vrml_Separator.hxx> |
54 | #include <Vrml_NormalBinding.hxx> |
55 | |
56 | |
57 | //========================================================================= |
58 | // function: Add |
59 | // purpose |
60 | //========================================================================= |
61 | void VrmlConverter_ShadedShape::Add( Standard_OStream& anOStream, |
62 | const TopoDS_Shape& aShape, |
63 | const Handle(VrmlConverter_Drawer)& aDrawer ) |
64 | { |
65 | |
66 | // here the triangulation is computed on the whole shape |
67 | // if it does not yet exist |
68 | |
69 | |
70 | Standard_Real theRequestedDeflection; |
71 | if(aDrawer->TypeOfDeflection() == Aspect_TOD_RELATIVE) // TOD_RELATIVE, TOD_ABSOLUTE |
72 | { |
73 | Bnd_Box box; |
74 | BRepBndLib::AddClose(aShape, box); |
75 | |
76 | Standard_Real Xmin, Xmax, Ymin, Ymax, Zmin, Zmax, diagonal; |
77 | box.Get( Xmin, Ymin, Zmin, Xmax, Ymax, Zmax ); |
78 | if (!(box.IsOpenXmin() || box.IsOpenXmax() || |
79 | box.IsOpenYmin() || box.IsOpenYmax() || |
80 | box.IsOpenZmin() || box.IsOpenZmax())) |
81 | { |
82 | |
83 | diagonal = Sqrt ((Xmax - Xmin)*( Xmax - Xmin) + ( Ymax - Ymin)*( Ymax - Ymin) + ( Zmax - Zmin)*( Zmax - Zmin)); |
84 | diagonal = Max(diagonal, Precision::Confusion()); |
85 | theRequestedDeflection = aDrawer->DeviationCoefficient() * diagonal; |
86 | } |
87 | else |
88 | { |
89 | diagonal =1000000.; |
90 | theRequestedDeflection = aDrawer->DeviationCoefficient() * diagonal; |
91 | } |
92 | // cout << "diagonal = "<< diagonal << endl; |
93 | // cout << "theRequestedDeflection = "<< theRequestedDeflection << endl; |
94 | |
95 | } |
96 | else |
97 | { |
98 | theRequestedDeflection = aDrawer->MaximalChordialDeviation(); |
99 | } |
100 | |
101 | if (!BRepTools::Triangulation(aShape,theRequestedDeflection)) |
102 | BRepMesh::Mesh(aShape,theRequestedDeflection); // computes and save the triangulation in the face. |
103 | |
104 | |
105 | Handle(Poly_Triangulation) T; |
106 | TopLoc_Location theLocation; |
107 | Standard_Integer i, j, k, decal, nnv, EI; |
108 | |
109 | Standard_Integer t[3], n[3]; |
110 | gp_Pnt p; |
111 | TopExp_Explorer ex; |
112 | |
113 | // counting phasis. This phasis will count the valid triangle |
114 | // and the vertices to allocate the correct size for the arrays: |
115 | |
116 | Standard_Integer nbTriangles = 0, nbVertices = 0; |
117 | |
118 | Standard_Integer nt, nnn, n1, n2, n3; |
119 | |
120 | // iterating on each face of the shape: |
121 | for (ex.Init(aShape, TopAbs_FACE); ex.More(); ex.Next()) { |
122 | // getting the face: |
123 | const TopoDS_Face& F = TopoDS::Face(ex.Current()); |
124 | // getting the triangulation of the face. The triangulation may not exist: |
125 | T = BRep_Tool::Triangulation(F, theLocation); |
126 | // number of triangles: |
127 | if (T.IsNull()) continue; //smh |
128 | nnn = T->NbTriangles(); |
129 | |
130 | const TColgp_Array1OfPnt& Nodes = T->Nodes(); |
131 | // getting a triangle. It is a triplet of indices in the node table: |
132 | const Poly_Array1OfTriangle& triangles = T->Triangles(); |
133 | |
134 | // Taking the nodes of the triangle, taking into account the orientation |
135 | // of the triangle. |
136 | for (nt = 1; nt <= nnn; nt++) { |
137 | if (F.Orientation() == TopAbs_REVERSED) |
138 | triangles(nt).Get(n1,n3,n2); |
139 | else |
140 | triangles(nt).Get(n1,n2,n3); |
141 | |
142 | const gp_Pnt& P1 = Nodes(n1); |
143 | const gp_Pnt& P2 = Nodes(n2); |
144 | const gp_Pnt& P3 = Nodes(n3); |
145 | // controlling whether the triangle correct from a 3d point of |
146 | // view: (the triangle may exist in the UV space but the |
147 | // in the 3d space a dimension is null for example) |
148 | gp_Vec V1(P1,P2); |
149 | if (V1.SquareMagnitude() > 1.e-10) { |
150 | gp_Vec V2(P2,P3); |
151 | if (V2.SquareMagnitude() > 1.e-10) { |
152 | gp_Vec V3(P3,P1); |
153 | if (V3.SquareMagnitude() > 1.e-10) { |
154 | V1.Normalize(); |
155 | V2.Normalize(); |
156 | V1.Cross(V2); |
157 | if (V1.SquareMagnitude() > 1.e-10) { |
158 | nbTriangles++; |
159 | } |
160 | } |
161 | } |
162 | } |
163 | } |
164 | nbVertices += T->NbNodes(); |
165 | } |
166 | |
167 | // cout << "nbTriangles = "<< nbTriangles << endl; |
168 | // cout << "nbVertices = "<< nbVertices << endl << endl; |
169 | |
170 | //---------------------------- |
171 | // now we are going to iterate again to build graphic data from the triangle. |
172 | if (nbVertices > 2 && nbTriangles > 0) { |
173 | // allocating the graphic arrays. |
174 | |
175 | Handle(VrmlConverter_ShadingAspect) SA = new VrmlConverter_ShadingAspect; |
176 | SA = aDrawer->ShadingAspect(); |
177 | |
178 | Handle(TColgp_HArray1OfVec) HAV1 = new TColgp_HArray1OfVec(1, nbVertices); |
179 | Handle(TColgp_HArray1OfVec) HAV2 = new TColgp_HArray1OfVec(1, nbVertices); |
180 | |
181 | gp_Vec V, VV; |
182 | |
183 | Handle(TColStd_HArray1OfInteger) HAI1 = new TColStd_HArray1OfInteger(1,4*nbTriangles); |
184 | Handle(TColStd_HArray1OfInteger) HAI3 = new TColStd_HArray1OfInteger(1,(nbVertices/3*4+nbVertices%3)); |
185 | Handle(TColStd_HArray1OfInteger) HAI2 = new TColStd_HArray1OfInteger(1,1); |
186 | Handle(TColStd_HArray1OfInteger) HAI4 = new TColStd_HArray1OfInteger(1,1); |
187 | |
188 | HAI2->SetValue (1,-1); |
189 | HAI4->SetValue (1,-1); |
190 | |
191 | // !! Specialize HAI2 - materialIndex HAI4 - textureCoordinateIndex |
192 | |
193 | EI = 1; |
194 | nnv = 1; |
195 | |
196 | for (ex.Init(aShape, TopAbs_FACE); ex.More(); ex.Next()) { |
197 | const TopoDS_Face& F = TopoDS::Face(ex.Current()); |
198 | T = BRep_Tool::Triangulation(F, theLocation); |
199 | if (!T.IsNull()) { |
200 | Poly_Connect pc(T); |
201 | |
202 | // 1 - Building HAV1 - array of all XYZ of nodes for Vrml_Coordinate3 from the triangles |
203 | // and HAV2 - array of all normals of nodes for Vrml_Normal |
204 | |
205 | const TColgp_Array1OfPnt& Nodes = T->Nodes(); |
206 | TColgp_Array1OfDir NORMAL(Nodes.Lower(), Nodes.Upper()); |
207 | |
208 | decal = nnv-1; |
209 | |
210 | for (j= Nodes.Lower(); j<= Nodes.Upper(); j++) { |
211 | p = Nodes(j).Transformed(theLocation.Transformation()); |
212 | |
213 | V.SetX(p.X()); V.SetY(p.Y()); V.SetZ(p.Z()); |
214 | HAV1->SetValue(nnv,V); |
215 | |
216 | if(SA->HasNormals()) |
217 | { |
218 | // to compute the normal. |
219 | ComputeNormal(F, pc, NORMAL); |
220 | |
221 | VV.SetX(NORMAL(j).X()); VV.SetY(NORMAL(j).Y()); VV.SetZ(NORMAL(j).Z()); |
222 | HAV2->SetValue(nnv,VV); |
223 | } |
224 | nnv++; |
225 | } |
226 | |
227 | // 2 - Building HAI1 - array of indexes of all triangles and |
228 | // HAI3 - array of indexes of all normales for Vrml_IndexedFaceSet |
229 | nbTriangles = T->NbTriangles(); |
230 | const Poly_Array1OfTriangle& triangles = T->Triangles(); |
231 | for (i = 1; i <= nbTriangles; i++) { |
232 | pc.Triangles(i,t[0],t[1],t[2]); |
233 | if (F.Orientation() == TopAbs_REVERSED) |
234 | triangles(i).Get(n[0],n[2],n[1]); |
235 | else |
236 | triangles(i).Get(n[0],n[1],n[2]); |
237 | const gp_Pnt& P1 = Nodes(n[0]); |
238 | const gp_Pnt& P2 = Nodes(n[1]); |
239 | const gp_Pnt& P3 = Nodes(n[2]); |
240 | gp_Vec V1(P1,P2); |
241 | if (V1.SquareMagnitude() > 1.e-10) { |
242 | gp_Vec V2(P2,P3); |
243 | if (V2.SquareMagnitude() > 1.e-10) { |
244 | gp_Vec V3(P3,P1); |
245 | if (V3.SquareMagnitude() > 1.e-10) { |
246 | V1.Normalize(); |
247 | V2.Normalize(); |
248 | V1.Cross(V2); |
249 | if (V1.SquareMagnitude() > 1.e-10) { |
250 | for (j = 0; j < 3; j++) { |
251 | |
252 | HAI1->SetValue(EI, n[j]+decal-1); // array of indexes of all triangles |
253 | EI++; |
254 | } |
255 | |
256 | HAI1->SetValue(EI, -1); |
257 | EI++; |
258 | } |
259 | } |
260 | } |
261 | } |
262 | } |
263 | } |
264 | } |
265 | |
266 | |
267 | if(SA->HasNormals()) |
268 | { |
269 | j=1; |
270 | for (i=HAI3->Lower(); i <= HAI3->Upper(); i++) |
271 | { |
272 | k = i % 4; |
273 | if (k == 0) |
274 | { |
275 | HAI3->SetValue(i, -1); |
276 | j++; |
277 | } |
278 | else |
279 | { |
280 | HAI3->SetValue(i, i-j); |
281 | } |
282 | } |
283 | } |
284 | |
285 | //----------------------------- |
286 | /* |
287 | cout << " ******************** " << endl; |
288 | cout << " Array HAV1 - Coordinare3 " << endl; |
289 | |
290 | for ( i=HAV1->Lower(); i <= HAV1->Upper(); i++ ) |
291 | { |
292 | cout << HAV1->Value(i).X() << " " << HAV1->Value(i).Y()<< " " << HAV1->Value(i).Z() << endl; |
293 | } |
294 | |
295 | if(SA->HasNormals()) |
296 | { |
297 | |
298 | cout << " ******************** " << endl; |
299 | cout << " Array HAV2 - Normals " << endl; |
300 | |
301 | for ( i=HAV2->Lower(); i <= HAV2->Upper(); i++ ) |
302 | { |
303 | cout << HAV2->Value(i).X() << " " << HAV2->Value(i).Y()<< " " << HAV2->Value(i).Z() << endl; |
304 | } |
305 | |
306 | cout << " ******************** " << endl; |
307 | cout << " Array HAI3 - normalIndex " << endl; |
308 | |
309 | for ( i=HAI3->Lower(); i <= HAI3->Upper(); i++ ) |
310 | { |
311 | cout << HAI3->Value(i) << endl; |
312 | } |
313 | |
314 | } |
315 | |
316 | cout << " ******************** " << endl; |
317 | cout << " Array HAI1 - coordIndex " << endl; |
318 | |
319 | for ( i=HAI1->Lower(); i <= HAI1->Upper(); i++ ) |
320 | { |
321 | cout << HAI1->Value(i) << endl; |
322 | } |
323 | |
324 | cout << " ******************** " << endl; |
325 | */ |
326 | //---------------------------- |
327 | |
328 | // creation of Vrml objects |
329 | |
330 | Vrml_ShapeHints SH; |
331 | SH = SA->ShapeHints(); |
332 | |
333 | if(SA->HasNormals()) |
334 | { |
335 | // Separator 1 { |
336 | Vrml_Separator SE1; |
337 | SE1.Print(anOStream); |
338 | // Material |
339 | if (SA->HasMaterial()){ |
340 | |
341 | Handle(Vrml_Material) M; |
342 | M = SA->FrontMaterial(); |
343 | |
344 | M->Print(anOStream); |
345 | } |
346 | |
347 | // Coordinate3 |
348 | Handle(Vrml_Coordinate3) C3 = new Vrml_Coordinate3(HAV1); |
349 | C3->Print(anOStream); |
350 | // ShapeHints |
351 | SH.Print(anOStream); |
352 | // NormalBinding |
353 | Vrml_MaterialBindingAndNormalBinding MBNB1 = Vrml_PER_VERTEX_INDEXED; |
354 | Vrml_NormalBinding NB(MBNB1); |
355 | NB.Print(anOStream); |
356 | // Separator 2 { |
357 | Vrml_Separator SE2; |
358 | SE2.Print(anOStream); |
359 | // Normal |
360 | Vrml_Normal N(HAV2); |
361 | N.Print(anOStream); |
362 | // IndexedFaceSet |
363 | Vrml_IndexedFaceSet IFS; |
364 | IFS.SetCoordIndex(HAI1); |
365 | IFS.SetNormalIndex(HAI3); |
366 | IFS.Print(anOStream); |
367 | // Separator 2 } |
368 | SE2.Print(anOStream); |
369 | // Separator 1 } |
370 | SE1.Print(anOStream); |
371 | } |
372 | else |
373 | { |
374 | // Separator 1 { |
375 | Vrml_Separator SE1; |
376 | SE1.Print(anOStream); |
377 | // Material |
378 | if (SA->HasMaterial()){ |
379 | |
380 | Handle(Vrml_Material) M; |
381 | M = SA->FrontMaterial(); |
382 | |
383 | M->Print(anOStream); |
384 | } |
385 | // Coordinate3 |
386 | Handle(Vrml_Coordinate3) C3 = new Vrml_Coordinate3(HAV1); |
387 | C3->Print(anOStream); |
388 | // ShapeHints |
389 | SH.Print(anOStream); |
390 | // IndexedFaceSet |
391 | Vrml_IndexedFaceSet IFS; |
392 | IFS.SetCoordIndex(HAI1); |
393 | IFS.Print(anOStream); |
394 | // Separator 1 } |
395 | SE1.Print(anOStream); |
396 | } |
397 | } |
398 | } |
399 | |
400 | |
401 | //--------- Notes ------------- |
402 | |
403 | // the necessary of calculation of Normals and Textures must be define in Drawer |
404 | // likes tolerance |
405 | |
406 | //---------- End on notes ------------ |
407 | |
408 | |
409 | |
410 | //---------------------------- |
411 | // Computing the normal |
412 | //----------------------------- |
413 | |
414 | void VrmlConverter_ShadedShape::ComputeNormal(const TopoDS_Face& aFace, |
415 | Poly_Connect& pc, |
416 | TColgp_Array1OfDir& Nor) |
417 | { |
418 | const Handle(Poly_Triangulation)& T = pc.Triangulation(); |
419 | BRepAdaptor_Surface S; |
420 | Standard_Boolean hasUV = T->HasUVNodes(); |
421 | Standard_Integer i; |
422 | TopLoc_Location l; |
423 | Handle(Geom_Surface) GS = BRep_Tool::Surface(aFace, l); |
424 | |
425 | if (hasUV && !GS.IsNull()) { |
426 | Standard_Boolean OK = Standard_True; |
427 | gp_Vec D1U,D1V; |
428 | gp_Vec D2U,D2V,D2UV; |
429 | gp_Pnt P; |
430 | Standard_Real U, V; |
431 | CSLib_DerivativeStatus Status; |
432 | CSLib_NormalStatus NStat; |
433 | S.Initialize(aFace); |
434 | const TColgp_Array1OfPnt2d& UVNodes = T->UVNodes(); |
435 | for (i = UVNodes.Lower(); i <= UVNodes.Upper(); i++) { |
436 | U = UVNodes(i).X(); |
437 | V = UVNodes(i).Y(); |
438 | S.D1(U,V,P,D1U,D1V); |
439 | CSLib::Normal(D1U,D1V,Precision::Angular(),Status,Nor(i)); |
440 | if (Status != CSLib_Done) { |
441 | S.D2(U,V,P,D1U,D1V,D2U,D2V,D2UV); |
442 | CSLib::Normal(D1U,D1V,D2U,D2V,D2UV,Precision::Angular(),OK,NStat,Nor(i)); |
443 | } |
444 | if (aFace.Orientation() == TopAbs_REVERSED) (Nor(i)).Reverse(); |
445 | } |
446 | } |
447 | else { |
448 | const TColgp_Array1OfPnt& Nodes = T->Nodes(); |
449 | Standard_Integer n[3]; |
450 | const Poly_Array1OfTriangle& triangles = T->Triangles(); |
451 | |
452 | for (i = Nodes.Lower(); i <= Nodes.Upper(); i++) { |
453 | gp_XYZ eqPlan(0, 0, 0); |
454 | for (pc.Initialize(i); pc.More(); pc.Next()) { |
455 | triangles(pc.Value()).Get(n[0], n[1], n[2]); |
456 | gp_XYZ v1(Nodes(n[1]).Coord()-Nodes(n[0]).Coord()); |
457 | gp_XYZ v2(Nodes(n[2]).Coord()-Nodes(n[1]).Coord()); |
458 | eqPlan += (v1^v2).Normalized(); |
459 | } |
460 | Nor(i) = gp_Dir(eqPlan); |
461 | if (aFace.Orientation() == TopAbs_REVERSED) (Nor(i)).Reverse(); |
462 | } |
463 | } |
464 | } |
465 | |
466 | |