0023404: Create SquareConfusion function in Precision package for speed and convenience
[occt.git] / src / NIS / NIS_Surface.cxx
1 // Created on: 2008-03-20
2 // Created by: Alexander GRIGORIEV
3 // Copyright (c) 2008-2012 OPEN CASCADE SAS
4 //
5 // The content of this file is subject to the Open CASCADE Technology Public
6 // License Version 6.5 (the "License"). You may not use the content of this file
7 // except in compliance with the License. Please obtain a copy of the License
8 // at http://www.opencascade.org and read it completely before using this file.
9 //
10 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
11 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
12 //
13 // The Original Code and all software distributed under the License is
14 // distributed on an "AS IS" basis, without warranty of any kind, and the
15 // Initial Developer hereby disclaims all such warranties, including without
16 // limitation, any warranties of merchantability, fitness for a particular
17 // purpose or non-infringement. Please see the License for the specific terms
18 // and conditions governing the rights and limitations under the License.
19
20
21 #include <NIS_Surface.hxx>
22 #include <NIS_SurfaceDrawer.hxx>
23 #include <NIS_Triangulated.hxx>
24 #include <BRepMesh_IncrementalMesh.hxx>
25 #include <BRep_ListIteratorOfListOfCurveRepresentation.hxx>
26 #include <BRep_PolygonOnTriangulation.hxx>
27 #include <BRep_TEdge.hxx>
28 #include <BRep_Tool.hxx>
29 #include <Geom_Surface.hxx>
30 #include <NCollection_Map.hxx>
31 #include <Poly_PolygonOnTriangulation.hxx>
32 #include <Poly_Triangulation.hxx>
33 #include <Precision.hxx>
34 #include <TColgp_Array1OfPnt2d.hxx>
35 #include <TopExp.hxx>
36 #include <TopExp_Explorer.hxx>
37 #include <TopLoc_Location.hxx>
38 #include <TopTools_MapOfShape.hxx>
39 #include <TopoDS.hxx>
40 #include <TopoDS_Face.hxx>
41 #include <TopoDS_Edge.hxx>
42 #include <TShort_Array1OfShortReal.hxx>
43 #include <gp_Ax1.hxx>
44
45 IMPLEMENT_STANDARD_HANDLE (NIS_Surface, NIS_InteractiveObject)
46 IMPLEMENT_STANDARD_RTTIEXT(NIS_Surface, NIS_InteractiveObject)
47
48 //=======================================================================
49 //function : IsEqual
50 //purpose  : Compare two triangulations, for NCollection_Map interface.
51 //=======================================================================
52
53 inline Standard_Boolean IsEqual(const Handle_Poly_Triangulation& theT0,
54                                 const Handle_Poly_Triangulation& theT1)
55 {
56   return (theT0 == theT1);
57 }
58
59 //=======================================================================
60 //function : NIS_Surface
61 //purpose  : 
62 //=======================================================================
63
64 NIS_Surface::NIS_Surface(const Handle_NCollection_BaseAllocator& theAlloc)
65   : myAlloc      (theAlloc),
66     mypNodes     (NULL),
67     mypNormals   (NULL),
68     mypTriangles (NULL),
69     mypEdges     (NULL),
70     myNNodes     (0),
71     myNTriangles (0),
72     myNEdges     (0),
73     myIsWireframe(0)
74 {
75   if (myAlloc.IsNull())
76     myAlloc = NCollection_BaseAllocator::CommonBaseAllocator();  
77 }
78
79 //=======================================================================
80 //function : NIS_Surface
81 //purpose  : 
82 //=======================================================================
83
84 NIS_Surface::NIS_Surface (const Handle(Poly_Triangulation)&       theTri,
85                           const Handle_NCollection_BaseAllocator& theAlloc)
86   : myAlloc      (theAlloc),
87     mypNodes     (NULL),
88     mypNormals   (NULL),
89     mypEdges     (NULL),
90     myNNodes     (0),
91     myNTriangles (0),
92     myNEdges     (0),
93     myIsWireframe(0)
94 {
95   if (myAlloc.IsNull())
96     myAlloc = NCollection_BaseAllocator::CommonBaseAllocator();
97   if (theTri.IsNull() == Standard_False)
98   {
99     // Alocate arrays of entities
100     myNNodes = 3 * theTri->NbTriangles();
101     myNTriangles = theTri->NbTriangles();
102     mypNodes = static_cast<Standard_ShortReal*>
103       (myAlloc->Allocate(sizeof(Standard_ShortReal) * 3 * myNNodes));
104     mypNormals = static_cast<Standard_ShortReal *>
105       (myAlloc->Allocate(sizeof(Standard_ShortReal) * 3 * myNNodes));
106     mypTriangles = static_cast<Standard_Integer*>
107       (myAlloc->Allocate(sizeof(Standard_Integer) * 3 * myNTriangles));
108
109     // Copy the data from the original triangulation.
110     Standard_Integer i, iN(0), iT(0);
111     const Poly_Array1OfTriangle& arrTri = theTri->Triangles();
112     const TColgp_Array1OfPnt& arrNodes = theTri->Nodes();
113     for (i = arrTri.Lower(); i <= arrTri.Upper(); i++) {
114       Standard_Integer iNode[3];
115       arrTri(i).Get(iNode[0], iNode[1], iNode[2]);
116       gp_XYZ aNorm = ((arrNodes(iNode[1]).XYZ() - arrNodes(iNode[0]).XYZ()) ^
117                       (arrNodes(iNode[2]).XYZ() - arrNodes(iNode[0]).XYZ()));
118       const Standard_Real aMagn = aNorm.Modulus();
119       if (aMagn > Precision::Confusion())
120         aNorm /= aMagn;
121       else
122         aNorm.SetCoord(0., 0., 1.);
123       mypNodes[iN+0] = static_cast<Standard_ShortReal>(arrNodes(iNode[0]).X());
124       mypNodes[iN+1] = static_cast<Standard_ShortReal>(arrNodes(iNode[0]).Y());
125       mypNodes[iN+2] = static_cast<Standard_ShortReal>(arrNodes(iNode[0]).Z());
126       mypNodes[iN+3] = static_cast<Standard_ShortReal>(arrNodes(iNode[1]).X());
127       mypNodes[iN+4] = static_cast<Standard_ShortReal>(arrNodes(iNode[1]).Y());
128       mypNodes[iN+5] = static_cast<Standard_ShortReal>(arrNodes(iNode[1]).Z());
129       mypNodes[iN+6] = static_cast<Standard_ShortReal>(arrNodes(iNode[2]).X());
130       mypNodes[iN+7] = static_cast<Standard_ShortReal>(arrNodes(iNode[2]).Y());
131       mypNodes[iN+8] = static_cast<Standard_ShortReal>(arrNodes(iNode[2]).Z());
132       mypNormals[iN+0] = static_cast<Standard_ShortReal>(aNorm.X());
133       mypNormals[iN+1] = static_cast<Standard_ShortReal>(aNorm.Y());
134       mypNormals[iN+2] = static_cast<Standard_ShortReal>(aNorm.Z());
135       mypNormals[iN+3] = static_cast<Standard_ShortReal>(aNorm.X());
136       mypNormals[iN+4] = static_cast<Standard_ShortReal>(aNorm.Y());
137       mypNormals[iN+5] = static_cast<Standard_ShortReal>(aNorm.Z());
138       mypNormals[iN+6] = static_cast<Standard_ShortReal>(aNorm.X());
139       mypNormals[iN+7] = static_cast<Standard_ShortReal>(aNorm.Y());
140       mypNormals[iN+8] = static_cast<Standard_ShortReal>(aNorm.Z());
141       mypTriangles[iT+0] = iT+0;
142       mypTriangles[iT+1] = iT+1;
143       mypTriangles[iT+2] = iT+2;
144       iN += 9;
145       iT += 3;
146     }
147   }
148 }
149
150 //=======================================================================
151 //function : NIS_Surface
152 //purpose  : Constructor
153 //=======================================================================
154
155 NIS_Surface::NIS_Surface (const TopoDS_Shape&                     theShape,
156                           const Standard_Real                     theDeflection,
157                           const Handle_NCollection_BaseAllocator& theAlloc)
158   : myAlloc       (theAlloc),
159     mypNodes      (NULL),
160     mypNormals    (NULL),
161     mypTriangles  (NULL),
162     mypEdges      (NULL),
163     myNNodes      (0),
164     myNTriangles  (0),
165     myNEdges      (0),
166     myIsWireframe (0)
167 {
168   if (myAlloc.IsNull())
169     myAlloc = NCollection_BaseAllocator::CommonBaseAllocator();
170   Init (theShape, theDeflection);
171 }
172
173 //=======================================================================
174 //function : Init
175 //purpose  : Initialize the instance with a TopoDS_Shape.
176 //=======================================================================
177
178 void NIS_Surface::Init (const TopoDS_Shape& theShape,
179                         const Standard_Real theDeflection)
180 {
181   TopLoc_Location  aLoc, aLocSurf;
182
183   // Count the nodes and triangles in faces
184   NCollection_Map<Handle_Poly_Triangulation> mapTri;
185   TopExp_Explorer fexp (theShape, TopAbs_FACE);
186   for (; fexp.More(); fexp.Next())
187   {
188     const TopoDS_Face& aFace = TopoDS::Face(fexp.Current());
189     
190     const Handle(Poly_Triangulation)& aTriangulation
191       = BRep_Tool::Triangulation (aFace, aLoc);
192     
193     if (aTriangulation.IsNull())
194       BRepMesh_IncrementalMesh aMeshTool(aFace, theDeflection); 
195
196     if (aTriangulation.IsNull() == Standard_False)
197     {
198       myNNodes     += aTriangulation->NbNodes();
199       myNTriangles += aTriangulation->NbTriangles();
200       mapTri.Add(aTriangulation);
201     }
202   }
203
204   // Create map of edges, to build wireframe for all edges.
205   TopTools_MapOfShape mapEdges;
206   TopExp_Explorer eexp (theShape, TopAbs_EDGE);
207   for (; eexp.More(); eexp.Next())
208   {
209     const TopoDS_Shape& anEdge = eexp.Current();
210     mapEdges.Add(anEdge);
211   }
212
213   // Allocate arrays of entities
214   if (myNNodes && myNTriangles) {
215     mypNodes = static_cast<Standard_ShortReal *>
216       (myAlloc->Allocate(sizeof(Standard_ShortReal) * 3 * myNNodes));
217     mypNormals = static_cast<Standard_ShortReal *>
218       (myAlloc->Allocate(sizeof(Standard_ShortReal) * 3 * myNNodes));
219     mypTriangles = static_cast<Standard_Integer *>
220       (myAlloc->Allocate(sizeof(Standard_Integer) * 3 * myNTriangles));
221     mypEdges = static_cast<Standard_Integer **>
222       (myAlloc->Allocate(sizeof(Standard_Integer *) * mapEdges.Extent()));
223     myNEdges = 0;
224
225     // The second loop: copy all nodes and triangles face-by-face
226     const Standard_Real eps2 = Precision::SquareConfusion();
227     Standard_Integer nNodes (0), nTriangles (0);
228     for (fexp.ReInit(); fexp.More(); fexp.Next())
229     {
230       const TopoDS_Face& aFace = TopoDS::Face(fexp.Current());
231       const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(aFace, aLocSurf);
232       const Handle(Poly_Triangulation)& aTriangulation =
233         BRep_Tool::Triangulation(aFace, aLoc);
234       if (aTriangulation.IsNull() == Standard_False)
235       {
236         // Prepare transformation
237         Standard_Integer i, aNodeInd(nNodes)/*, aNTriangles = 0*/;
238         const gp_Trsf&   aTrf     = aLoc.Transformation();
239         const gp_Trsf&   aTrfSurf = aLocSurf.Transformation();
240         Standard_Boolean isReverse = (aFace.Orientation() == TopAbs_REVERSED);
241
242         // Store all nodes of the current face in the data model
243         const TColgp_Array1OfPnt&   tabNode = aTriangulation->Nodes();
244         const TColgp_Array1OfPnt2d& tabUV   = aTriangulation->UVNodes();
245         for (i = tabNode.Lower(); i <= tabNode.Upper(); i++)
246         {
247           Standard_Real t[3];
248           tabNode(i).Transformed(aTrf).Coord (t[0], t[1], t[2]);
249           //  write node to mesh data
250           mypNodes[3*aNodeInd + 0] = static_cast<Standard_ShortReal>(t[0]);
251           mypNodes[3*aNodeInd + 1] = static_cast<Standard_ShortReal>(t[1]);
252           mypNodes[3*aNodeInd + 2] = static_cast<Standard_ShortReal>(t[2]);
253
254           gp_Vec aD1U, aD1V;
255           gp_Pnt aP;
256           gp_XYZ aNorm(0., 0., 0.);
257
258           if (aTriangulation->HasNormals()) {
259             // Retrieve the normal direction from the triangulation
260             aNorm.SetCoord(aTriangulation->Normals().Value(3*i-2),
261                            aTriangulation->Normals().Value(3*i-1),
262                            aTriangulation->Normals().Value(3*i-0));
263           } else if (aSurf.IsNull() == Standard_False)
264           {
265             // Compute the surface normal at the Node.
266             aSurf->D1(tabUV(i).X(), tabUV(i).Y(), aP, aD1U, aD1V);
267             aNorm = (aD1U.Crossed(aD1V)).XYZ();
268           }
269
270           if (isReverse)
271             aNorm.Reverse();
272           const Standard_Real aMod = aNorm.SquareModulus();
273           if (aMod > eps2) {
274             gp_Dir aDirNorm(aNorm);
275             aDirNorm.Transform(aTrfSurf);
276             aDirNorm.Coord (t[0], t[1], t[2]);
277           } else {
278             t[0] = 0.;
279             t[1] = 0.;
280             t[2] = 1.;
281           }
282           mypNormals[3*aNodeInd + 0] = static_cast<Standard_ShortReal>(t[0]);
283           mypNormals[3*aNodeInd + 1] = static_cast<Standard_ShortReal>(t[1]);
284           mypNormals[3*aNodeInd + 2] = static_cast<Standard_ShortReal>(t[2]);
285
286           aNodeInd++;
287         }
288         const Standard_Integer nNodes1 = nNodes - 1;
289         // Store all triangles of the current face in the data model
290         const Poly_Array1OfTriangle& tabTri  = aTriangulation->Triangles();
291         for (i = tabTri.Lower(); i <= tabTri.Upper(); i++)
292         {
293           Standard_Integer aN[3];
294           tabTri(i).Get (aN[0], aN[1], aN[2]);
295           Standard_Integer * pTriangle = &mypTriangles[nTriangles*3];
296           pTriangle[0] = aN[0] + nNodes1;
297           if (isReverse) {
298             pTriangle[1] = aN[2] + nNodes1;
299             pTriangle[2] = aN[1] + nNodes1;
300           } else {
301             pTriangle[1] = aN[1] + nNodes1;
302             pTriangle[2] = aN[2] + nNodes1;
303           }
304           const Standard_ShortReal aVec0[3] = {
305             mypNodes[3*pTriangle[1]+0] - mypNodes[3*pTriangle[0]+0],
306             mypNodes[3*pTriangle[1]+1] - mypNodes[3*pTriangle[0]+1],
307             mypNodes[3*pTriangle[1]+2] - mypNodes[3*pTriangle[0]+2]
308           };
309           const Standard_ShortReal aVec1[3] = {
310             mypNodes[3*pTriangle[2]+0] - mypNodes[3*pTriangle[0]+0],
311             mypNodes[3*pTriangle[2]+1] - mypNodes[3*pTriangle[0]+1],
312             mypNodes[3*pTriangle[2]+2] - mypNodes[3*pTriangle[0]+2]
313           };
314           const Standard_ShortReal aVecP[3] = {
315             aVec0[1] * aVec1[2] - aVec0[2] * aVec1[1],
316             aVec0[2] * aVec1[0] - aVec0[0] * aVec1[2],
317             aVec0[0] * aVec1[1] - aVec0[1] * aVec1[0]
318           };
319           if (aVecP[0]*aVecP[0] + aVecP[1]*aVecP[1] + aVecP[2]*aVecP[2] > eps2)
320             nTriangles++;
321         }
322         // Store all edge polygons on the current face.
323         for (eexp.Init(aFace, TopAbs_EDGE); eexp.More(); eexp.Next())
324         {
325           const TopoDS_Edge& anEdge = TopoDS::Edge(eexp.Current());
326           if (mapEdges.Remove(anEdge)) {
327             const Handle(Poly_PolygonOnTriangulation)& aPolygon =
328               BRep_Tool::PolygonOnTriangulation(anEdge, aTriangulation, aLoc);
329             if (aPolygon.IsNull() == Standard_False) {
330               const TColStd_Array1OfInteger& arrNode = aPolygon->Nodes();
331               // Allocate memory to store the current polygon indices.
332               Standard_Integer aLen = arrNode.Length();
333               Standard_Integer * pEdge = static_cast<Standard_Integer *>
334                 (myAlloc->Allocate(sizeof(Standard_Integer) * (aLen + 1)));
335               const gp_Pnt* pLast = &tabNode(arrNode(arrNode.Lower()));
336               pEdge[1] = arrNode(arrNode.Lower()) + nNodes1;
337               Standard_Integer iPNode(arrNode.Lower() + 1), iENode(1);
338               for (; iPNode <= arrNode.Upper(); iPNode++)
339               {
340                 const Standard_Integer aN(arrNode(iPNode));
341                 if (pLast->SquareDistance(tabNode(aN)) < eps2)
342                 {
343                   aLen--;
344                 } else {
345                   pLast = &tabNode(aN);
346                   pEdge[++iENode] = aN + nNodes1;
347                 }
348               }
349               // Do not save very short polygons
350               if (aLen > 1) {
351                 pEdge[0] = aLen;
352                 mypEdges[myNEdges++] = pEdge;
353               }
354             }
355           }
356         }
357         nNodes += tabNode.Length();
358       }
359     }
360     myNTriangles = nTriangles;
361   }
362   if (GetDrawer().IsNull() == Standard_False)
363   {
364     setDrawerUpdate();
365   }
366   setIsUpdateBox(Standard_True);  
367 }
368
369 //=======================================================================
370 //function : ~NIS_Surface
371 //purpose  : Destructor
372 //=======================================================================
373
374 NIS_Surface::~NIS_Surface ()
375 {
376   Clear();
377 }
378
379 //=======================================================================
380 //function : Clear
381 //purpose  : 
382 //=======================================================================
383
384 void NIS_Surface::Clear ()
385 {
386   if (myNNodes) {
387     myNNodes = 0;
388     myAlloc->Free(mypNodes);
389     myAlloc->Free(mypNormals);
390   }
391   if (myNTriangles) {
392     myNTriangles = 0;
393     myAlloc->Free(mypTriangles);
394   }
395   if (mypEdges) {
396     for (Standard_Integer i = 0; i < myNEdges; i++) {
397       myAlloc->Free(mypEdges[i]);
398     }
399     myNEdges = 0;
400     myAlloc->Free(mypEdges);
401   }
402   if (GetDrawer().IsNull() == Standard_False) {
403     GetDrawer()->SetUpdated(NIS_Drawer::Draw_Normal,
404                             NIS_Drawer::Draw_Top,
405                             NIS_Drawer::Draw_Transparent,
406                             NIS_Drawer::Draw_Hilighted);
407   }
408   myBox.Clear();
409 }
410
411 //=======================================================================
412 //function : DefaultDrawer
413 //purpose  : 
414 //=======================================================================
415
416 NIS_Drawer * NIS_Surface::DefaultDrawer (NIS_Drawer * theDrawer) const
417 {
418   NIS_SurfaceDrawer * aDrawer =
419     theDrawer ? static_cast<NIS_SurfaceDrawer *>(theDrawer)
420               : new NIS_SurfaceDrawer (Quantity_NOC_SLATEBLUE4);
421   aDrawer->SetBackColor (Quantity_NOC_DARKGREEN);
422   aDrawer->myIsWireframe = myIsWireframe;
423   return aDrawer;
424 }
425
426 //=======================================================================
427 //function : SetColor
428 //purpose  : Set the normal color for presentation.
429 //=======================================================================
430
431 void NIS_Surface::SetColor (const Quantity_Color&  theColor)
432 {
433   const Handle(NIS_SurfaceDrawer) aDrawer =
434     static_cast<NIS_SurfaceDrawer *>(DefaultDrawer(0L));
435   aDrawer->Assign (GetDrawer());
436   aDrawer->myColor[NIS_Drawer::Draw_Normal] = theColor;
437   aDrawer->myColor[NIS_Drawer::Draw_Top] = theColor;
438   aDrawer->myColor[NIS_Drawer::Draw_Transparent] = theColor;
439   SetDrawer (aDrawer);
440 }
441
442 //=======================================================================
443 //function : SetBackColor
444 //purpose  : Set the normal color for presentation of back side of triangles.
445 //=======================================================================
446
447 void NIS_Surface::SetBackColor (const Quantity_Color&  theColor)
448 {
449   const Handle(NIS_SurfaceDrawer) aDrawer =
450     static_cast<NIS_SurfaceDrawer *>(DefaultDrawer(0L));
451   aDrawer->Assign (GetDrawer());
452   aDrawer->myBackColor = theColor;
453   SetDrawer (aDrawer);
454 }
455
456 //=======================================================================
457 //function : SetPolygonOffset
458 //purpose  : 
459 //=======================================================================
460
461 void NIS_Surface::SetPolygonOffset (const Standard_Real theValue)
462 {
463   const Handle(NIS_SurfaceDrawer) aDrawer =
464     static_cast<NIS_SurfaceDrawer *>(DefaultDrawer(0L));
465   aDrawer->Assign (GetDrawer());
466   aDrawer->myPolygonOffset = static_cast<Standard_ShortReal>(theValue);
467   SetDrawer (aDrawer);
468 }
469
470 //=======================================================================
471 //function : SetDisplayMode
472 //purpose  : Set the display mode: Shading or Wireframe.
473 //=======================================================================
474
475 void  NIS_Surface::SetDisplayMode (const NIS_Surface::DisplayMode theMode)
476 {
477   Standard_Boolean isUpdate(Standard_False);
478   if (myIsWireframe) {
479     if (theMode != Wireframe) {
480       myIsWireframe = Standard_False;
481       isUpdate = Standard_True;
482     }
483   } else {
484     if (theMode == Wireframe) {
485       myIsWireframe = Standard_True;
486       isUpdate = Standard_True;
487     }
488   }
489   if (isUpdate && !GetDrawer().IsNull()) {
490     const Handle(NIS_SurfaceDrawer) aDrawer =
491       static_cast<NIS_SurfaceDrawer *>(DefaultDrawer(0L));
492     aDrawer->Assign (GetDrawer());
493     aDrawer->myIsWireframe = myIsWireframe;
494     SetDrawer(aDrawer);
495   }
496 }
497
498 //=======================================================================
499 //function : GetDisplayMode
500 //purpose  : Query the current display mode: Shading or Wireframe.
501 //=======================================================================
502
503 NIS_Surface::DisplayMode NIS_Surface::GetDisplayMode () const
504 {
505   return myIsWireframe ? Wireframe : Shading;
506 }
507
508 //=======================================================================
509 //function : Clone
510 //purpose  : 
511 //=======================================================================
512
513 void NIS_Surface::Clone (const Handle_NCollection_BaseAllocator& theAlloc,
514                          Handle_NIS_InteractiveObject&           theDest) const
515 {
516   Handle(NIS_Surface) aNewObj;
517   if (theDest.IsNull()) {
518     aNewObj = new NIS_Surface(theAlloc);
519     theDest = aNewObj;
520   } else {
521     aNewObj = reinterpret_cast<NIS_Surface*> (theDest.operator->());
522     aNewObj->myAlloc = theAlloc;
523   }
524   NIS_InteractiveObject::Clone(theAlloc, theDest);
525   aNewObj->myNNodes = myNNodes;
526   if (myNNodes > 0) {
527     // copy nodes and normals
528     const Standard_Size nBytes = myNNodes*3*sizeof(Standard_ShortReal);
529     aNewObj->mypNodes = (Standard_ShortReal *)theAlloc->Allocate(nBytes);
530     aNewObj->mypNormals = (Standard_ShortReal *)theAlloc->Allocate(nBytes);
531     memcpy(aNewObj->mypNodes, mypNodes, nBytes);
532     memcpy(aNewObj->mypNormals, mypNormals, nBytes);
533   }
534   aNewObj->myNTriangles = myNTriangles;
535   if (myNTriangles > 0) {
536     const Standard_Size nBytes = sizeof(Standard_Integer) * 3 * myNTriangles;
537     aNewObj->mypTriangles = (Standard_Integer *)theAlloc->Allocate(nBytes);
538     memcpy(aNewObj->mypTriangles, mypTriangles, nBytes);
539   }
540   aNewObj->myNEdges = myNEdges;
541   if (myNEdges > 0) {
542     aNewObj->mypEdges = static_cast<Standard_Integer **>
543       (theAlloc->Allocate(sizeof(Standard_Integer *) * myNEdges));
544     for (Standard_Integer i = 0; i < myNEdges; i++) {
545       const Standard_Integer * pEdge = mypEdges[i];
546       const Standard_Size nBytes = sizeof(Standard_Integer) * (pEdge[0] + 1);
547       aNewObj->mypEdges[i] =
548         static_cast<Standard_Integer *> (theAlloc->Allocate(nBytes));
549       memcpy(aNewObj->mypEdges[i], pEdge, nBytes);
550     }
551   }
552   aNewObj->myIsWireframe = myIsWireframe;
553 }
554
555 //=======================================================================
556 //function : Intersect
557 //purpose  : 
558 //=======================================================================
559
560 Standard_Real NIS_Surface::Intersect (const gp_Ax1&       theAxis,
561                                       const Standard_Real theOver) const
562 {
563   Standard_Real aResult (RealLast());
564   Standard_Real start[3], dir[3];
565   theAxis.Location().Coord(start[0], start[1], start[2]);
566   theAxis.Direction().Coord(dir[0], dir[1], dir[2]);
567   double anInter;
568
569   if (myIsWireframe == Standard_False)
570     for (Standard_Integer i = 0; i < myNTriangles; i++) {
571       const Standard_Integer * pTri = &mypTriangles[3*i];
572       if (NIS_Triangulated::tri_line_intersect (start, dir,
573                                                 &mypNodes[3*pTri[0]],
574                                                 &mypNodes[3*pTri[1]],
575                                                 &mypNodes[3*pTri[2]],
576                                                 &anInter))
577         if (anInter < aResult)
578           aResult = anInter;
579     }
580   else {
581     const Standard_Real anOver2 = theOver*theOver;
582     for (Standard_Integer iEdge = 0; iEdge < myNEdges; iEdge++) {
583       const Standard_Integer * anEdge = mypEdges[iEdge];
584       const Standard_Integer nNodes = anEdge[0];
585       for (Standard_Integer i = 1; i < nNodes; i++) {
586         // Node index is incremented for the head of polygon indice array
587         if (NIS_Triangulated::seg_line_intersect (theAxis.Location().XYZ(),
588                                                   theAxis.Direction().XYZ(),
589                                                   anOver2,
590                                                   &mypNodes[3*anEdge[i+0]],
591                                                   &mypNodes[3*anEdge[i+1]],
592                                                   &anInter))
593           if (anInter < aResult)
594             aResult = anInter;
595       }
596     }
597   }
598
599   return aResult;
600 }
601
602 //=======================================================================
603 //function : Intersect
604 //purpose  : 
605 //=======================================================================
606
607 Standard_Boolean NIS_Surface::Intersect (const Bnd_B3f&         theBox,
608                                          const gp_Trsf&         theTrf,
609                                          const Standard_Boolean isFullIn) const
610 {
611   Standard_Boolean aResult (isFullIn);
612
613   if (myIsWireframe == Standard_False) {
614     if (myNTriangles > 0) {
615       for (Standard_Integer iNode = 0; iNode < myNNodes*3; iNode+=3) {
616         gp_XYZ aPnt (static_cast<Standard_Real>(mypNodes[iNode+0]),
617                      static_cast<Standard_Real>(mypNodes[iNode+1]),
618                      static_cast<Standard_Real>(mypNodes[iNode+2]));
619         theTrf.Transforms(aPnt);
620         if (theBox.IsOut (aPnt) == isFullIn) {
621           aResult = !isFullIn;
622           break;
623         }
624       }
625     }
626   } else {
627     for (Standard_Integer iEdge = 0; iEdge < myNEdges; iEdge++) {
628       const Standard_Integer * anEdge = mypEdges[iEdge];
629       const Standard_Integer nNodes = anEdge[0];
630       for (Standard_Integer i = 1; i < nNodes; i++) {
631         // index is incremented by 1 for the head number in the array
632         gp_Pnt aPnt[2] = {
633           gp_Pnt(static_cast<Standard_Real>(mypNodes[3*anEdge[i+0]+0]),
634                  static_cast<Standard_Real>(mypNodes[3*anEdge[i+0]+1]),
635                  static_cast<Standard_Real>(mypNodes[3*anEdge[i+0]+2])),
636           gp_Pnt(static_cast<Standard_Real>(mypNodes[3*anEdge[i+1]+0]),
637                  static_cast<Standard_Real>(mypNodes[3*anEdge[i+1]+1]),
638                  static_cast<Standard_Real>(mypNodes[3*anEdge[i+1]+2]))
639         };
640         aPnt[0].Transform(theTrf);
641         aPnt[1].Transform(theTrf);
642         if (isFullIn) {
643           if (NIS_Triangulated::seg_box_included (theBox, aPnt) == 0) {
644             aResult = Standard_False;
645             break;
646           }
647         } else {
648           if (NIS_Triangulated::seg_box_intersect (theBox, aPnt)) {
649             aResult = Standard_True;
650             break;
651           }
652         }
653       }
654     }
655   }
656   return aResult;
657 }
658
659 //=======================================================================
660 //function : Intersect
661 //purpose  : Selection by polygon
662 //=======================================================================
663
664 Standard_Boolean NIS_Surface::Intersect
665                     (const NCollection_List<gp_XY> &thePolygon,
666                      const gp_Trsf                 &theTrf,
667                      const Standard_Boolean         isFullIn) const
668 {
669   Standard_Boolean aResult (isFullIn);
670
671   if (myIsWireframe == Standard_False) {
672     if (myNTriangles > 0) {
673       for (Standard_Integer iNode = 0; iNode < myNNodes*3; iNode+=3) {
674         gp_XYZ aPnt (static_cast<Standard_Real>(mypNodes[iNode+0]),
675                      static_cast<Standard_Real>(mypNodes[iNode+1]),
676                      static_cast<Standard_Real>(mypNodes[iNode+2]));
677         theTrf.Transforms(aPnt);
678         gp_XY aP2d(aPnt.X(), aPnt.Y());
679
680         if (!NIS_Triangulated::IsIn(thePolygon, aP2d)) {
681           if (isFullIn) {
682             aResult = Standard_False;
683             break;
684           }
685         } else {
686           if (isFullIn == Standard_False) {
687             aResult = Standard_True;
688             break;
689           }
690         }
691       }
692     }
693   } else {
694     for (Standard_Integer iEdge = 0; iEdge < myNEdges; iEdge++) {
695       const Standard_Integer * anEdge = mypEdges[iEdge];
696       const Standard_Integer nNodes = anEdge[0];
697       for (Standard_Integer i = 1; i < nNodes; i++) {
698         // index is incremented by 1 for the head number in the array
699         gp_Pnt aPnt[2] = {
700           gp_Pnt(static_cast<Standard_Real>(mypNodes[3*anEdge[i+0]+0]),
701                  static_cast<Standard_Real>(mypNodes[3*anEdge[i+0]+1]),
702                  static_cast<Standard_Real>(mypNodes[3*anEdge[i+0]+2])),
703           gp_Pnt(static_cast<Standard_Real>(mypNodes[3*anEdge[i+1]+0]),
704                  static_cast<Standard_Real>(mypNodes[3*anEdge[i+1]+1]),
705                  static_cast<Standard_Real>(mypNodes[3*anEdge[i+1]+2]))
706         };
707         aPnt[0].Transform(theTrf);
708         aPnt[1].Transform(theTrf);
709         const gp_XY aP2d[2] = { gp_XY(aPnt[0].X(), aPnt[0].Y()),
710                                 gp_XY(aPnt[1].X(), aPnt[1].Y()) };
711         if (isFullIn) {
712           if (NIS_Triangulated::seg_polygon_included (thePolygon, aP2d) == 0) {
713             aResult = Standard_False;
714             break;
715           }
716         } else {
717           if (NIS_Triangulated::seg_polygon_intersect (thePolygon, aP2d)) {
718             aResult = Standard_True;
719             break;
720           }
721         }
722       }
723     }
724   }
725   return aResult;
726 }
727
728 //=======================================================================
729 //function : computeBox
730 //purpose  : 
731 //=======================================================================
732
733 void NIS_Surface::computeBox ()
734 {
735   NIS_Triangulated::ComputeBox(myBox, myNNodes, mypNodes, 3);
736
737   const Handle(NIS_SurfaceDrawer)& aDrawer =
738     static_cast<const Handle(NIS_SurfaceDrawer)&> (GetDrawer());
739
740   if (aDrawer.IsNull() == Standard_False) {
741     const gp_Trsf& aTrsf = aDrawer->GetTransformation();
742     myBox = myBox.Transformed(aTrsf);
743   }
744 }