abb15a86162c10f83d6a5b3b78711b649cd8f00e
[occt.git] / src / NIS / NIS_Surface.cxx
1 // File:      NIS_Surface.cpp
2 // Created:   20.03.08 08:27
3 // Author:    Alexander GRIGORIEV
4 // Copyright: Open Cascade S.A. 2008
5
6 #include <NIS_Surface.hxx>
7 #include <NIS_SurfaceDrawer.hxx>
8 #include <NIS_Triangulated.hxx>
9 #include <BRep_Tool.hxx>
10 #include <Geom_Surface.hxx>
11 #include <Poly_Triangulation.hxx>
12 #include <Precision.hxx>
13 #include <TColgp_Array1OfPnt2d.hxx>
14 #include <TopExp_Explorer.hxx>
15 #include <TopLoc_Location.hxx>
16 #include <TopoDS.hxx>
17 #include <TopoDS_Face.hxx>
18 #include <gp_Ax1.hxx>
19
20 IMPLEMENT_STANDARD_HANDLE (NIS_Surface, NIS_InteractiveObject)
21 IMPLEMENT_STANDARD_RTTIEXT(NIS_Surface, NIS_InteractiveObject)
22
23 //=======================================================================
24 //function : defaultDrawer
25 //purpose  : internal method (static)
26 //=======================================================================
27
28 inline Handle(NIS_SurfaceDrawer) defaultDrawer()
29 {
30   const Handle(NIS_SurfaceDrawer) aDrawer =
31     new NIS_SurfaceDrawer(Quantity_NOC_SLATEBLUE4);
32   aDrawer->SetBackColor (Quantity_NOC_DARKGREEN);
33   return aDrawer;
34 }
35
36 //=======================================================================
37 //function : NIS_Surface
38 //purpose  : 
39 //=======================================================================
40
41 NIS_Surface::NIS_Surface
42                         (const Handle(Poly_Triangulation)&       theTri,
43                          const Handle_NCollection_BaseAllocator& theAlloc)
44 : mypNodes              (NULL),
45   mypNormals            (NULL),
46   myNNodes              (0),
47   myNTriangles          (0),
48   myAlloc               (theAlloc)
49 {
50   if (myAlloc.IsNull())
51     myAlloc = NCollection_BaseAllocator::CommonBaseAllocator();
52   if (theTri.IsNull() == Standard_False)
53   {
54     // Alocate arrays of entities
55     myNNodes = 3 * theTri->NbTriangles();
56     myNTriangles = theTri->NbTriangles();
57     mypNodes = static_cast<Standard_ShortReal*>
58       (myAlloc->Allocate(sizeof(Standard_ShortReal) * 3 * myNNodes));
59     mypNormals = static_cast<Standard_ShortReal *>
60       (myAlloc->Allocate(sizeof(Standard_ShortReal) * 3 * myNNodes));
61     mypTriangles = static_cast<Standard_Integer*>
62       (myAlloc->Allocate(sizeof(Standard_Integer) * 3 * myNTriangles));
63
64     // Copy the data from the original triangulation.
65     Standard_Integer i, iN(0), iT(0);
66     const Poly_Array1OfTriangle& arrTri = theTri->Triangles();
67     const TColgp_Array1OfPnt& arrNodes = theTri->Nodes();
68     for (i = arrTri.Lower(); i <= arrTri.Upper(); i++) {
69       Standard_Integer iNode[3];
70       arrTri(i).Get(iNode[0], iNode[1], iNode[2]);
71       gp_XYZ aNorm = ((arrNodes(iNode[1]).XYZ() - arrNodes(iNode[0]).XYZ()) ^
72                       (arrNodes(iNode[2]).XYZ() - arrNodes(iNode[0]).XYZ()));
73       const Standard_Real aMagn = aNorm.Modulus();
74       if (aMagn > Precision::Confusion())
75         aNorm /= aMagn;
76       else
77         aNorm.SetCoord(0., 0., 1.);
78       mypNodes[iN+0] = static_cast<Standard_ShortReal>(arrNodes(iNode[0]).X());
79       mypNodes[iN+1] = static_cast<Standard_ShortReal>(arrNodes(iNode[0]).Y());
80       mypNodes[iN+2] = static_cast<Standard_ShortReal>(arrNodes(iNode[0]).Z());
81       mypNodes[iN+3] = static_cast<Standard_ShortReal>(arrNodes(iNode[1]).X());
82       mypNodes[iN+4] = static_cast<Standard_ShortReal>(arrNodes(iNode[1]).Y());
83       mypNodes[iN+5] = static_cast<Standard_ShortReal>(arrNodes(iNode[1]).Z());
84       mypNodes[iN+6] = static_cast<Standard_ShortReal>(arrNodes(iNode[2]).X());
85       mypNodes[iN+7] = static_cast<Standard_ShortReal>(arrNodes(iNode[2]).Y());
86       mypNodes[iN+8] = static_cast<Standard_ShortReal>(arrNodes(iNode[2]).Z());
87       mypNormals[iN+0] = static_cast<Standard_ShortReal>(aNorm.X());
88       mypNormals[iN+1] = static_cast<Standard_ShortReal>(aNorm.Y());
89       mypNormals[iN+2] = static_cast<Standard_ShortReal>(aNorm.Z());
90       mypNormals[iN+3] = static_cast<Standard_ShortReal>(aNorm.X());
91       mypNormals[iN+4] = static_cast<Standard_ShortReal>(aNorm.Y());
92       mypNormals[iN+5] = static_cast<Standard_ShortReal>(aNorm.Z());
93       mypNormals[iN+6] = static_cast<Standard_ShortReal>(aNorm.X());
94       mypNormals[iN+7] = static_cast<Standard_ShortReal>(aNorm.Y());
95       mypNormals[iN+8] = static_cast<Standard_ShortReal>(aNorm.Z());
96       mypTriangles[iT+0] = iT+0;
97       mypTriangles[iT+1] = iT+1;
98       mypTriangles[iT+2] = iT+2;
99       iN += 9;
100       iT += 3;
101     }
102   }
103 }
104
105 //=======================================================================
106 //function : NIS_Surface
107 //purpose  : Constructor
108 //=======================================================================
109
110 NIS_Surface::NIS_Surface
111                             (const TopoDS_Shape&                theShape,
112 //                           const Standard_Real                theDeflection,
113                              const Handle_NCollection_BaseAllocator& theAlloc)
114   : mypNodes      (NULL),
115     mypNormals    (NULL),
116     mypTriangles  (NULL),
117     myNNodes      (0),
118     myNTriangles  (0),
119     myAlloc       (theAlloc)
120 {
121   if (myAlloc.IsNull())
122     myAlloc = NCollection_BaseAllocator::CommonBaseAllocator();
123   TopLoc_Location  aLoc, aLocSurf;
124
125   // Count the nodes and triangles in faces
126   TopExp_Explorer fexp (theShape, TopAbs_FACE);
127   for ( ; fexp.More(); fexp.Next() )
128   {
129     TopoDS_Face aFace = TopoDS::Face(fexp.Current());
130     
131     const Handle(Poly_Triangulation)& aTriangulation
132       = BRep_Tool::Triangulation (aFace, aLoc);
133     const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(aFace, aLoc);
134
135     if (aTriangulation.IsNull() == Standard_False &&
136         aSurf.IsNull() == Standard_False)
137     {
138       myNNodes     += aTriangulation->NbNodes();
139       myNTriangles += aTriangulation->NbTriangles();
140     }
141   }
142
143   // Alocate arrays of entities
144   if (myNNodes && myNTriangles) {
145     mypNodes = static_cast<Standard_ShortReal*>
146       (myAlloc->Allocate(sizeof(Standard_ShortReal) * 3 * myNNodes));
147     mypNormals = static_cast<Standard_ShortReal *>
148       (myAlloc->Allocate(sizeof(Standard_ShortReal) * 3 * myNNodes));
149     mypTriangles = static_cast<Standard_Integer*>
150       (myAlloc->Allocate(sizeof(Standard_Integer) * 3 * myNTriangles));
151
152     // The second loop: copy all nodes and triangles face-by-face
153     const Standard_Real eps2 = Precision::Confusion()*Precision::Confusion();
154     Standard_Integer nNodes (0), nTriangles (0);
155     for (fexp.ReInit(); fexp.More(); fexp.Next())
156     {
157       const TopoDS_Face& aFace = TopoDS::Face(fexp.Current());
158       const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(aFace, aLocSurf);
159       const Handle(Poly_Triangulation)& aTriangulation =
160         BRep_Tool::Triangulation(aFace, aLoc);
161       if (aTriangulation.IsNull() == Standard_False &&
162           aSurf.IsNull() == Standard_False)
163       {
164         // Prepare transformation
165         Standard_Integer i, aNodeInd(nNodes)/*, aNTriangles = 0*/;
166         const gp_Trsf&   aTrf     = aLoc.Transformation();
167         const gp_Trsf&   aTrfSurf = aLocSurf.Transformation();
168         Standard_Boolean isReverse = (aFace.Orientation() == TopAbs_REVERSED);
169
170         // Store all nodes of the current face in the data model
171         const TColgp_Array1OfPnt&   tabNode = aTriangulation->Nodes();
172         const TColgp_Array1OfPnt2d& tabUV   = aTriangulation->UVNodes();
173         for (i = tabNode.Lower(); i <= tabNode.Upper(); i++)
174         {
175           Standard_Real t[3];
176           tabNode(i).Transformed(aTrf).Coord (t[0], t[1], t[2]);
177           //  write node to mesh data
178           mypNodes[3*aNodeInd + 0] = static_cast<Standard_ShortReal>(t[0]);
179           mypNodes[3*aNodeInd + 1] = static_cast<Standard_ShortReal>(t[1]);
180           mypNodes[3*aNodeInd + 2] = static_cast<Standard_ShortReal>(t[2]);
181
182           gp_Vec aD1U, aD1V;
183           gp_Pnt aP;
184
185           // Compute the surface normal at the Node.
186           aSurf->D1(tabUV(i).X(), tabUV(i).Y(), aP, aD1U, aD1V);
187           gp_XYZ aNorm = (aD1U.Crossed(aD1V)).XYZ();
188           if (isReverse)
189             aNorm.Reverse();
190           const Standard_Real aMod = aNorm.SquareModulus();
191           if (aMod > eps2) {
192             gp_Dir aDirNorm(aNorm);
193             aDirNorm.Transform(aTrfSurf);
194             aDirNorm.Coord (t[0], t[1], t[2]);
195           } else {
196             t[0] = 0.;
197             t[1] = 0.;
198             t[2] = 1.;
199           }
200           mypNormals[3*aNodeInd + 0] = static_cast<Standard_ShortReal>(t[0]);
201           mypNormals[3*aNodeInd + 1] = static_cast<Standard_ShortReal>(t[1]);
202           mypNormals[3*aNodeInd + 2] = static_cast<Standard_ShortReal>(t[2]);
203
204           aNodeInd++;
205         }
206         // Store all triangles of the current face in the data model
207         const Poly_Array1OfTriangle& tabTri  = aTriangulation->Triangles();
208         for (i = tabTri.Lower(); i <= tabTri.Upper(); i++)
209         {
210           Standard_Integer aN[3];
211           tabTri(i).Get (aN[0], aN[1], aN[2]);
212           if (((tabNode(aN[2]).XYZ() -
213                 tabNode(aN[0]).XYZ()) ^
214                (tabNode(aN[1]).XYZ() -
215                 tabNode(aN[0]).XYZ())).SquareModulus() > eps2)
216           {
217             aN[0] += (nNodes - 1);
218             aN[1] += (nNodes - 1);
219             aN[2] += (nNodes - 1);
220             mypTriangles[nTriangles*3 + 0] = aN[0];
221             if (isReverse) {
222               mypTriangles[nTriangles*3 + 1] = aN[2];
223               mypTriangles[nTriangles*3 + 2] = aN[1];
224             } else {
225               mypTriangles[nTriangles*3 + 1] = aN[1];
226               mypTriangles[nTriangles*3 + 2] = aN[2];
227             }
228             nTriangles++;
229           }
230         }
231         nNodes += tabNode.Length();
232       }
233     }
234     myNTriangles = nTriangles;
235   }
236 }
237
238 //=======================================================================
239 //function : ~NIS_Surface
240 //purpose  : Destructor
241 //=======================================================================
242
243 NIS_Surface::~NIS_Surface ()
244 {
245   if (myNNodes) {
246     myNNodes = 0;
247     myAlloc->Free(mypNodes);
248     myAlloc->Free(mypNormals);
249   }
250   if (myNTriangles) {
251     myNTriangles = 0;
252     myAlloc->Free(mypTriangles);
253   }
254 }
255
256 //=======================================================================
257 //function : DefaultDrawer
258 //purpose  : 
259 //=======================================================================
260
261 Handle(NIS_Drawer) NIS_Surface::DefaultDrawer () const
262 {
263   return defaultDrawer();
264 }
265
266 //=======================================================================
267 //function : SetColor
268 //purpose  : Set the normal color for presentation.
269 //=======================================================================
270
271 void NIS_Surface::SetColor (const Quantity_Color&  theColor)
272 {
273   Handle(NIS_SurfaceDrawer) aDrawer = defaultDrawer();
274   aDrawer->Assign (GetDrawer());
275   aDrawer->myColor[NIS_Drawer::Draw_Normal] = theColor;
276   aDrawer->myColor[NIS_Drawer::Draw_Transparent] = theColor;
277   SetDrawer (aDrawer);
278 }
279
280 //=======================================================================
281 //function : SetBackColor
282 //purpose  : Set the normal color for presentation of back side of triangles.
283 //=======================================================================
284
285 void NIS_Surface::SetBackColor (const Quantity_Color&  theColor)
286 {
287   Handle(NIS_SurfaceDrawer) aDrawer = defaultDrawer();
288   aDrawer->Assign (GetDrawer());
289   aDrawer->myBackColor = theColor;
290   SetDrawer (aDrawer);
291 }
292
293 //=======================================================================
294 //function : SetPolygonOffset
295 //purpose  : 
296 //=======================================================================
297
298 void NIS_Surface::SetPolygonOffset (const Standard_Real theValue)
299 {
300   Handle(NIS_SurfaceDrawer) aDrawer = defaultDrawer();
301   aDrawer->Assign (GetDrawer());
302   aDrawer->myPolygonOffset = theValue;
303   SetDrawer (aDrawer);
304 }
305
306 //=======================================================================
307 //function : SetTransparency
308 //purpose  : 
309 //=======================================================================
310
311 void NIS_Surface::SetTransparency (const Standard_Real theValue)
312 {
313   Handle(NIS_SurfaceDrawer) aDrawer = defaultDrawer();
314   aDrawer->Assign (GetDrawer());
315   aDrawer->myTransparency = theValue;
316   SetDrawer (aDrawer);
317 }
318
319 //=======================================================================
320 //function : Intersect
321 //purpose  : 
322 //=======================================================================
323
324 Standard_Real NIS_Surface::Intersect (const gp_Ax1&       theAxis,
325                                             const Standard_Real /*over*/) const
326 {
327   Standard_Real aResult (RealLast());
328   Standard_Real start[3], dir[3];
329   theAxis.Location().Coord(start[0], start[1], start[2]);
330   theAxis.Direction().Coord(dir[0], dir[1], dir[2]);
331   double anInter;
332
333   for (Standard_Integer i = 0; i < myNTriangles; i++) {
334     const Standard_Integer * pTri = &mypTriangles[3*i];
335     if (NIS_Triangulated::tri_line_intersect (start, dir,
336                                               &mypNodes[3*pTri[0]],
337                                               &mypNodes[3*pTri[1]],
338                                               &mypNodes[3*pTri[2]],
339                                               &anInter))
340       if (anInter < aResult)
341         aResult = anInter;
342   }
343
344   return aResult;
345 }
346
347 //=======================================================================
348 //function : Intersect
349 //purpose  : 
350 //=======================================================================
351
352 Standard_Boolean NIS_Surface::Intersect
353                                         (const Bnd_B3f&         theBox,
354                                          const gp_Trsf&         theTrf,
355                                          const Standard_Boolean isFullIn) const
356 {
357   Standard_Boolean aResult (isFullIn);
358
359   if (myNTriangles > 0) {
360     for (Standard_Integer iNode = 0; iNode < myNNodes*3; iNode+=3) {
361       gp_XYZ aPnt (static_cast<Standard_Real>(mypNodes[iNode+0]),
362                    static_cast<Standard_Real>(mypNodes[iNode+1]),
363                    static_cast<Standard_Real>(mypNodes[iNode+2]));
364       theTrf.Transforms(aPnt);
365       if (theBox.IsOut (aPnt) == isFullIn) {
366         aResult = !isFullIn;
367         break;
368       }
369     }
370   }
371   return aResult;
372 }
373
374 //=======================================================================
375 //function : computeBox
376 //purpose  : 
377 //=======================================================================
378
379 void NIS_Surface::computeBox ()
380 {
381   NIS_Triangulated::ComputeBox(myBox, myNNodes, mypNodes);
382
383   const Handle(NIS_SurfaceDrawer)& aDrawer =
384     static_cast<const Handle(NIS_SurfaceDrawer)&> (GetDrawer());
385
386   if (aDrawer.IsNull() == Standard_False) {
387     const gp_Trsf& aTrsf = aDrawer->GetTransformation();
388     myBox = myBox.Transformed(aTrsf);
389   }
390 }