Update testing case for issue 0024499
[occt.git] / src / IntPoly / IntPoly_PlaneSection.cxx
1 // Created on: 1995-07-17
2 // Created by: Stagiaire Alain JOURDAIN
3 // Copyright (c) 1995-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and / or modify it
9 // under the terms of the GNU Lesser General Public version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #include <IntPoly_PlaneSection.ixx>
18
19 #include <IntPoly_SequenceOfSequenceOfPnt2d.hxx>
20 #include <IntPoly_IndexedMapOfPnt2d.hxx>
21 #include <IntPoly_Pnt2dHasher.hxx>
22 #include <Precision.hxx>
23 #include <TopExp_Explorer.hxx>
24 #include <TopoDS_Shape.hxx>
25 #include <TopoDS_Edge.hxx>
26 #include <BRep_Tool.hxx>
27 #include <BRep_Builder.hxx>
28 #include <TopoDS.hxx>
29 #include <Poly_Triangulation.hxx>
30 #include <Poly_Polygon3D.hxx>
31 #include <OSD_Chronometer.hxx>
32
33
34 //=======================================================================
35 //function : IntPoly_PlaneSection
36 //purpose  : 
37 //=======================================================================
38
39 IntPoly_PlaneSection::IntPoly_PlaneSection()
40 {}
41
42
43 //=======================================================================
44 //function : IntPoly_PlaneSection
45 //purpose  : 
46 //=======================================================================
47
48 IntPoly_PlaneSection::IntPoly_PlaneSection(const TopoDS_Shape& S,
49                                            const gp_Pln& P)
50 {
51   myShape = S;
52   myTransform.SetTransformation(P.Position()); 
53   gp_Ax3 Ax0(gp_Pnt(0,0,0),gp_Dir(0,0,1));
54   myBackTransform.SetTransformation(P.Position(),Ax0);
55   Section();
56 }
57
58
59 //=======================================================================
60 //function : Section
61 //purpose  : 
62 //=======================================================================
63
64 void IntPoly_PlaneSection::Section()
65
66   TopExp_Explorer ex;
67   Standard_Integer NbTrian,i,i1,i2,i3,Result;
68   Standard_Real Big = Precision::Infinite();
69   Standard_Boolean Inter;
70   //gp_Pnt Nod1,Nod2,Nod3;
71   gp_Pnt2d BegPoint,EndPoint,OutPoint;
72   TopLoc_Location Loc;
73   Handle(Poly_Triangulation) Tr;
74   myCpt = 0;
75   
76   for (ex.Init(myShape,TopAbs_FACE);ex.More();ex.Next()) {
77     Tr = (BRep_Tool::Triangulation(TopoDS::Face(ex.Current()),Loc));
78     if (!Tr.IsNull()) {
79       NbTrian = Tr->NbTriangles();
80       const Poly_Array1OfTriangle& TabTrian = Tr->Triangles();
81       const TColgp_Array1OfPnt&    TabNodes = Tr->Nodes();
82       TColgp_Array1OfPnt  TabTransfNodes(1,Tr->NbNodes());      
83       for (i = 1;i <= Tr->NbNodes();i++) {
84         if (!Loc.IsIdentity())
85           TabTransfNodes(i) = 
86             (TabNodes(i).Transformed(Loc.Transformation()))
87               .Transformed(myTransform);
88         else 
89           TabTransfNodes(i) = TabNodes(i).Transformed(myTransform);
90       }
91       for (i = 1;i <= NbTrian;i++) {
92         TabTrian(i).Get(i1,i2,i3);
93         Inter = Intersect(TabTransfNodes(i1),
94                           TabTransfNodes(i2),
95                           TabTransfNodes(i3),
96                           BegPoint,EndPoint);
97         if (Inter) {
98           if (myMapBegPoints.Contains(BegPoint)) {
99             Standard_Integer Index = myMapBegPoints.FindIndex(BegPoint);
100             Insert(myMapEndPoints.FindKey(Index),BegPoint,EndPoint);
101             myCpt++;
102             myMapBegPoints.Substitute(Index,gp_Pnt2d(Big,myCpt));
103             myMapEndPoints.Substitute(Index,gp_Pnt2d(Big,myCpt));
104           }
105           else if (myMapEndPoints.Contains(EndPoint)) {
106             Standard_Integer Index = myMapEndPoints.FindIndex(EndPoint);
107             Insert(myMapBegPoints.FindKey(Index),EndPoint,BegPoint);
108             myCpt++;
109             myMapBegPoints.Substitute(Index,gp_Pnt2d(Big,myCpt));
110             myMapEndPoints.Substitute(Index,gp_Pnt2d(Big,myCpt));
111           }
112           else {
113             myMapBegPoints.Add(BegPoint);
114             myMapEndPoints.Add(EndPoint);
115           }  
116         }
117       }
118     } 
119   }
120   
121   Standard_Integer NbLinks = myMapBegPoints.Extent();
122   i = 1;
123   while (i <= NbLinks) {
124     if (!(Precision::IsInfinite((myMapBegPoints.FindKey(i)).X()))) {
125       BegPoint = myMapBegPoints.FindKey(i);
126       EndPoint = myMapEndPoints.FindKey(i);
127       myCpt++;
128       myMapBegPoints.Substitute(i,gp_Pnt2d(Big,myCpt));
129       myMapEndPoints.Substitute(i,gp_Pnt2d(Big,myCpt));
130       Result = Concat(BegPoint,EndPoint,OutPoint);
131       if (Result == 2) 
132         ForwConstruction(OutPoint);
133       else
134         if (Result == 1)
135           PrevConstruction(OutPoint);
136         else {
137           ForwConstruction(EndPoint);
138           PrevConstruction(BegPoint);   
139         }
140     }
141     i++;
142   }
143   
144   i = 1;
145   while (i < mySection.Length()) {
146     ConcatSection(mySection.ChangeValue(i),mySection.Length(),i+1);
147     i++;
148   }
149   myNbEdges = mySection.Length();
150 }
151
152
153 //=======================================================================
154 //function : Intersect
155 //purpose  : Determines the 2 2D-points resulting of the intersection
156 //           of the triangle (Point1,Point2,Point3) by the plane
157 //=======================================================================
158
159 Standard_Boolean IntPoly_PlaneSection::Intersect(const gp_Pnt& Point1,
160                                                  const gp_Pnt& Point2,
161                                                  const gp_Pnt& Point3,
162                                                  gp_Pnt2d& OutPoint1,
163                                                  gp_Pnt2d& OutPoint2)
164 {
165   gp_Pnt Pt1 = Point1;
166   gp_Pnt Pt2 = Point2;
167   gp_Pnt Pt3 = Point3;
168   Standard_Real z1 = Pt1.Z();
169   Standard_Real z2 = Pt2.Z();
170   Standard_Real z3 = Pt3.Z();
171   Standard_Boolean intersection = Standard_False;
172
173   if ((z1 == 0) && (z2 == 0) && (z3 == 0)) 
174     return intersection;
175   if ((z1 == 0) && (z2 == 0)) {
176     intersection = Standard_True;
177     OutPoint1.SetCoord(Pt1.X(),Pt1.Y());
178     OutPoint2.SetCoord(Pt2.X(),Pt2.Y());
179     return intersection;
180   }
181   if ((z2 == 0) && (z3 == 0)) {
182     intersection = Standard_True;
183     OutPoint1.SetCoord(Pt2.X(),Pt2.Y());
184     OutPoint2.SetCoord(Pt3.X(),Pt3.Y());
185     return intersection;
186   }
187   if ((z3 == 0) && (z1 == 0)) {
188     intersection = Standard_True;
189     OutPoint1.SetCoord(Pt3.X(),Pt3.Y());
190     OutPoint2.SetCoord(Pt1.X(),Pt1.Y());
191     return intersection;
192   }
193   if (z1 == 0) {
194     if ((z2 < 0) && (z3 > 0)) 
195       intersection = Standard_True;
196     if ((z2 > 0) && (z3 < 0)) {
197       intersection = Standard_True;
198       gp_Pnt Pt = Pt2;
199       Pt2 = Pt3;
200       Pt3 = Pt; 
201     }
202     if (intersection) {
203       Standard_Real u1 = Pt2.X();
204       Standard_Real v1 = Pt2.Y();
205       z1 = Pt2.Z();
206       Standard_Real u2 = Pt3.X();
207       Standard_Real v2 = Pt3.Y();
208       z2 = Pt3.Z();
209       Standard_Real U = u1 - z1 * (u2 - u1)/(z2 - z1);
210       Standard_Real V = v1 - z1 * (v2 - v1)/(z2 - z1);
211       OutPoint1.SetCoord(Pt1.X(),Pt1.Y());
212       OutPoint2.SetCoord(U,V); 
213       return intersection;
214     }
215   }
216   else
217     if (z2 == 0) {
218       if ((z1 < 0) && (z3 > 0)) 
219         intersection = Standard_True;
220       if ((z1 > 0) && (z3 < 0)) {
221         intersection = Standard_True;
222         gp_Pnt Pt = Pt1;
223         Pt1 = Pt3;
224         Pt3 = Pt; 
225       }
226       if (intersection) {
227         Standard_Real u1 = Pt1.X();
228         Standard_Real v1 = Pt1.Y();
229         z1 = Pt1.Z();
230         Standard_Real u2 = Pt3.X();
231         Standard_Real v2 = Pt3.Y();
232         z2 = Pt3.Z();
233         Standard_Real U = u1 - z1 * (u2 - u1)/(z2 - z1);
234         Standard_Real V = v1 - z1 * (v2 - v1)/(z2 - z1);
235         OutPoint1.SetCoord(Pt2.X(),Pt2.Y());
236         OutPoint2.SetCoord(U,V); 
237         return intersection;
238       }
239     }
240     else
241       if (z3 == 0) {
242         if ((z2 < 0) && (z1 > 0)) 
243           intersection = Standard_True;
244         if ((z2 > 0) && (z1 < 0)) {
245           intersection = Standard_True;
246           gp_Pnt Pt = Pt2;
247           Pt2 = Pt1;
248           Pt1 = Pt; 
249         }
250         if (intersection) {
251           Standard_Real u1 = Pt2.X();
252           Standard_Real v1 = Pt2.Y();
253           z1 = Pt2.Z();
254           Standard_Real u2 = Pt1.X();
255           Standard_Real v2 = Pt1.Y();
256           z2 = Pt1.Z();
257           Standard_Real U = u1 - z1 * (u2 - u1)/(z2 - z1);
258           Standard_Real V = v1 - z1 * (v2 - v1)/(z2 - z1);
259           OutPoint1.SetCoord(Pt3.X(),Pt3.Y());
260           OutPoint2.SetCoord(U,V); 
261           return intersection;
262         }
263       }
264   
265   if ((z1 < 0) && (z2 > 0)) 
266     intersection = Standard_True;
267   if ((z1 > 0) && (z2 < 0)) { 
268     intersection = Standard_True;
269     gp_Pnt Pt = Pt1;
270     Pt1 = Pt2;
271     Pt2 = Pt; 
272   }
273   if (intersection) {
274     Standard_Real u1 = Pt1.X();
275     Standard_Real v1 = Pt1.Y();
276     z1 = Pt1.Z();
277     Standard_Real u2 = Pt2.X();
278     Standard_Real v2 = Pt2.Y();
279     z2 = Pt2.Z();
280     Standard_Real U = u1 - z1 * (u2 - u1)/(z2 - z1);
281     Standard_Real V = v1 - z1 * (v2 - v1)/(z2 - z1);
282     OutPoint1.SetCoord(U,V); 
283     intersection = Standard_False;
284     Pt1 = Point1;
285     Pt2 = Point2;
286     z1 = Pt1.Z();
287     z2 = Pt2.Z();
288     if ((z2 < 0) && (z3 > 0)) 
289       intersection = Standard_True;
290     if ((z2 > 0) && (z3 < 0)) {
291       intersection = Standard_True;
292       gp_Pnt Pt = Pt2;
293       Pt2 = Pt3;
294       Pt3 = Pt; 
295     }
296     if (intersection) {
297       u1 = Pt2.X();
298       v1 = Pt2.Y();
299       z1 = Pt2.Z();
300       u2 = Pt3.X();
301       v2 = Pt3.Y();
302       z2 = Pt3.Z();
303       U = u1 - z1 * (u2 - u1)/(z2 - z1);
304       V = v1 - z1 * (v2 - v1)/(z2 - z1);
305       OutPoint2.SetCoord(U,V); 
306       return intersection;
307     }
308     else {
309       intersection = Standard_True;
310       Pt3 = Point3;
311       z3 = Pt3.Z();
312       if ((z3 > 0) && (z1 < 0)) {
313         gp_Pnt Pt = Pt3;
314         Pt3 = Pt1;
315         Pt1 = Pt; 
316       }
317       u1 = Pt3.X();
318       v1 = Pt3.Y();
319       z1 = Pt3.Z();
320       u2 = Pt1.X();
321       v2 = Pt1.Y();
322       z2 = Pt1.Z();
323       U = u1 - z1 * (u2 - u1)/(z2 - z1);
324       V = v1 - z1 * (v2 - v1)/(z2 - z1);
325       OutPoint2.SetCoord(U,V); 
326       return intersection;
327     }
328   }
329   else {
330     if ((z2 < 0) && (z3 > 0)) 
331       intersection = Standard_True;
332     if ((z2 > 0) && (z3 < 0)) {
333       intersection = Standard_True;
334       gp_Pnt Pt = Pt2;
335       Pt2 = Pt3;
336       Pt3 = Pt; 
337     }
338     if (intersection) {
339       Standard_Real u1 = Pt2.X();
340       Standard_Real v1 = Pt2.Y();
341       z1 = Pt2.Z();
342       Standard_Real u2 = Pt3.X();
343       Standard_Real v2 = Pt3.Y();
344       z2 = Pt3.Z();
345       Standard_Real U = u1 - z1 * (u2 - u1)/(z2 - z1);
346       Standard_Real V = v1 - z1 * (v2 - v1)/(z2 - z1);
347       OutPoint1.SetCoord(U,V); 
348       Pt3 = Point3;
349       z3 = Pt3.Z();
350       if ((z3 > 0) && (z1 < 0)) {
351         gp_Pnt Pt = Pt3;
352         Pt3 = Pt1;
353         Pt1 = Pt; 
354       }
355       u1 = Pt3.X();
356       v1 = Pt3.Y();
357       z1 = Pt3.Z();
358       u2 = Pt1.X();
359       v2 = Pt1.Y();
360       z2 = Pt1.Z();
361       U = u1 - z1 * (u2 - u1)/(z2 - z1);
362       V = v1 - z1 * (v2 - v1)/(z2 - z1);
363       OutPoint2.SetCoord(U,V); 
364       return intersection;
365     }
366   }
367   return intersection;
368 }
369
370
371 //=======================================================================
372 //function : Insert
373 //purpose  : Sees whether OldPnt and NewPnt begins or ends a section
374 //           created before and adds the 2 others points.
375 //           If not, creates a section
376 //=======================================================================
377
378 void IntPoly_PlaneSection::Insert(const gp_Pnt2d& OldPnt,
379                                   const gp_Pnt2d& ComPnt,
380                                   const gp_Pnt2d& NewPnt)
381 {
382   Standard_Integer i = 0;
383   Standard_Integer NbSection = mySection.Length();
384   Standard_Boolean IsInSection = Standard_False;
385   
386   while (i < NbSection) {
387     i++;
388     TColgp_SequenceOfPnt2d& CurSection = mySection.ChangeValue(i);
389     if (IntPoly_Pnt2dHasher::IsEqual(OldPnt,CurSection.First())) {
390       IsInSection = Standard_True;
391       CurSection.Prepend(ComPnt);
392       CurSection.Prepend(NewPnt);
393       break;
394     }
395     if (IntPoly_Pnt2dHasher::IsEqual(OldPnt,CurSection.Last())) {
396       IsInSection = Standard_True;
397       CurSection.Append(ComPnt);
398       CurSection.Append(NewPnt);
399       break;
400     }
401     if (IntPoly_Pnt2dHasher::IsEqual(NewPnt,CurSection.First())) {
402       IsInSection = Standard_True;
403       CurSection.Prepend(ComPnt);
404       CurSection.Prepend(OldPnt);
405       break;
406     }
407     if (IntPoly_Pnt2dHasher::IsEqual(NewPnt,CurSection.Last())) {
408       IsInSection = Standard_True;
409       CurSection.Append(ComPnt);
410       CurSection.Append(OldPnt);
411       break;
412     }
413   }
414   if (!(IsInSection)) {
415     TColgp_SequenceOfPnt2d EmptySec;
416     EmptySec.Append(OldPnt);
417     EmptySec.Append(ComPnt);
418     EmptySec.Append(NewPnt);
419     mySection.Append(EmptySec);
420   }  
421 }
422
423
424 //=======================================================================
425 //function : Concat
426 //purpose  : sees whether BegPnt or EndPnt begins or ends a section
427 //           created before, and returns the other point to continue 
428 //           the construction
429 //           Returns 2 if the construction is 'Forward'
430 //           Returns 1 if the construction is 'Previous'
431 //           Returns 0 if not and creates a section
432 //=======================================================================
433
434 Standard_Integer IntPoly_PlaneSection::Concat(const gp_Pnt2d& BegPnt,
435                                               const gp_Pnt2d& EndPnt,
436                                               gp_Pnt2d& OutPnt)
437 {
438   Standard_Integer i = 0;
439   Standard_Integer NbSection = mySection.Length();
440   Standard_Integer ConcatIdx = 0;
441   
442   while (i < NbSection) {
443     i++;
444     TColgp_SequenceOfPnt2d& CurSection = mySection.ChangeValue(i);
445     if (IntPoly_Pnt2dHasher::IsEqual(BegPnt,CurSection.First())) {
446       ConcatIdx = 1;
447       myIndex = i;
448       CurSection.Prepend(EndPnt);
449       OutPnt = EndPnt;
450       break;
451     }
452     if (IntPoly_Pnt2dHasher::IsEqual(BegPnt,CurSection.Last())) {
453       ConcatIdx = 2;
454       myIndex = i;
455       CurSection.Append(EndPnt);
456       OutPnt = EndPnt;
457       break;
458     }
459     if (IntPoly_Pnt2dHasher::IsEqual(EndPnt,CurSection.First())) {
460       ConcatIdx = 1;
461       myIndex = i;
462       CurSection.Prepend(BegPnt);
463       OutPnt = BegPnt;
464       break;
465     }
466     if (IntPoly_Pnt2dHasher::IsEqual(EndPnt,CurSection.Last())) {
467       ConcatIdx = 2;
468       myIndex = i;
469       CurSection.Append(BegPnt);
470       OutPnt = BegPnt;
471       break;
472     }
473   }
474   if (ConcatIdx == 0) {
475     TColgp_SequenceOfPnt2d EmptySec;
476     EmptySec.Append(BegPnt);
477     EmptySec.Append(EndPnt);
478     mySection.Append(EmptySec);
479     NbSection++;
480     myIndex = NbSection;
481   }  
482   return ConcatIdx;
483 }
484
485
486 //=======================================================================
487 //function : ConcatSection
488 //purpose  : Sees whether Section begins or ends another one in  mySection,
489 //           from the rank 'Index' to the last one 'NbSection'
490 //=======================================================================
491
492 void IntPoly_PlaneSection::ConcatSection(TColgp_SequenceOfPnt2d& Section,
493                                          const Standard_Integer NbSection,
494                                          const Standard_Integer Index)
495 {
496   Standard_Integer j;
497   Standard_Integer i = Index;
498   gp_Pnt2d BegPnt = Section.First();
499   gp_Pnt2d EndPnt = Section.Last();
500
501   while (i <= NbSection) {
502     TColgp_SequenceOfPnt2d& CurSection = mySection.ChangeValue(i);
503     Standard_Integer CurSection_Length = CurSection.Length(); 
504     if (IntPoly_Pnt2dHasher::IsEqual(BegPnt,CurSection.First())) {
505       for (j = 2;j <= CurSection_Length;j++) 
506         Section.Prepend(CurSection.Value(j));
507       mySection.Remove(i);
508       ConcatSection(Section,NbSection-1,Index);
509       break;
510     }
511     else
512       if (IntPoly_Pnt2dHasher::IsEqual(BegPnt,CurSection.Last())) {
513         for (j = CurSection_Length-1;j >= 1;j--) 
514           Section.Prepend(CurSection.Value(j));
515         mySection.Remove(i);
516         ConcatSection(Section,NbSection-1,Index);
517         break;
518       }
519       else
520         if (IntPoly_Pnt2dHasher::IsEqual(EndPnt,CurSection.First())) {
521           for (j = 2;j <= CurSection_Length;j++) 
522             Section.Append(CurSection.Value(j));
523           mySection.Remove(i);
524           ConcatSection(Section,NbSection-1,Index);
525           break;
526         }
527         else
528           if (IntPoly_Pnt2dHasher::IsEqual(EndPnt,CurSection.Last())) {
529             for (j = CurSection_Length-1;j >= 1;j--) 
530               Section.Append(CurSection.Value(j));
531             mySection.Remove(i);
532             ConcatSection(Section,NbSection-1,Index);
533             break;
534           }
535     i++;
536   }
537 }
538
539
540 //=======================================================================
541 //function : ForwContruction
542 //purpose  : Builds a section from Point in this way  
543 //                    ___   ___   ___   ___
544 //               <---/__/--/__/--/__/--/__/--Point
545 //=======================================================================
546
547 void IntPoly_PlaneSection::ForwConstruction(const gp_Pnt2d& Point)
548 {
549   if (myMapBegPoints.Contains(Point)) {
550     Standard_Integer Index = myMapBegPoints.FindIndex(Point);
551     gp_Pnt2d Pnt = myMapEndPoints.FindKey(Index);
552     (mySection.ChangeValue(myIndex)).Append(Pnt);
553     Standard_Real Big = Precision::Infinite();
554     myCpt++;
555     myMapBegPoints.Substitute(Index,gp_Pnt2d(Big,myCpt));
556     myMapEndPoints.Substitute(Index,gp_Pnt2d(Big,myCpt));
557     ForwConstruction(Pnt);
558   }
559 }
560
561
562 //=======================================================================
563 //function : PrevContruction
564 //purpose  : Builds a section from Point in this way  
565 //                      ___   ___   ___   ___
566 //              Point--/__/--/__/--/__/--/__/--->
567 //=======================================================================
568
569 void IntPoly_PlaneSection::PrevConstruction(const gp_Pnt2d& Point)
570 {
571   if (myMapEndPoints.Contains(Point)) {
572     Standard_Integer Index = myMapEndPoints.FindIndex(Point);
573     gp_Pnt2d Pnt = myMapBegPoints.FindKey(Index);
574     (mySection.ChangeValue(myIndex)).Prepend(Pnt);
575     Standard_Real Big = Precision::Infinite();
576     myCpt++;
577     myMapBegPoints.Substitute(Index,gp_Pnt2d(Big,myCpt));
578     myMapEndPoints.Substitute(Index,gp_Pnt2d(Big,myCpt));
579     PrevConstruction(Pnt);
580   }
581 }
582
583
584 //=======================================================================
585 //function : NbEdges
586 //purpose  : Returns the final number of edges in the section
587 //=======================================================================
588
589 Standard_Integer IntPoly_PlaneSection::NbEdges()
590 { return myNbEdges; }
591
592
593 //=======================================================================
594 //function : Edge
595 //purpose  : Builds the edges of the section
596 //=======================================================================
597
598 TopoDS_Edge IntPoly_PlaneSection::Edge(const Standard_Integer Index)
599 {
600   const TColgp_SequenceOfPnt2d& CurSection = mySection.ChangeValue(Index);
601   Standard_Integer NbPoints = CurSection.Length();
602   TColgp_Array1OfPnt TabPnt(1,NbPoints);
603   gp_Pnt CurPoint;
604   for (Standard_Integer i = 1 ; i <= NbPoints ; i++) {
605     CurPoint.SetX((CurSection.Value(i)).X());
606     CurPoint.SetY((CurSection.Value(i)).Y());
607     CurPoint.SetZ(0);
608     TabPnt.SetValue(i,CurPoint.Transformed(myBackTransform));
609   }
610   Handle(Poly_Polygon3D) Pol = new Poly_Polygon3D(TabPnt);
611   TopoDS_Edge Edge;
612   BRep_Builder B;
613   B.MakeEdge(Edge,Pol);
614   return Edge;
615 }
616
617
618
619
620
621
622
623