0031431: Visualization, PrsMgr_PresentableObject - simplify HLR computing interface
[occt.git] / src / AIS / AIS_IdenticRelation.cxx
1 // Created on: 1997-03-03
2 // Created by: Jean-Pierre COMBE
3 // Copyright (c) 1997-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 under
9 // the terms of the GNU Lesser General Public License 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
18 #include <AIS.hxx>
19 #include <AIS_IdenticRelation.hxx>
20 #include <AIS_Shape.hxx>
21 #include <BRep_Tool.hxx>
22 #include <DsgPrs_IdenticPresentation.hxx>
23 #include <ElCLib.hxx>
24 #include <Geom_Circle.hxx>
25 #include <Geom_Ellipse.hxx>
26 #include <Geom_Line.hxx>
27 #include <Geom_Plane.hxx>
28 #include <Geom_Transformation.hxx>
29 #include <Geom_TrimmedCurve.hxx>
30 #include <GeomAPI_ProjectPointOnCurve.hxx>
31 #include <gp_Dir.hxx>
32 #include <gp_Pln.hxx>
33 #include <gp_Pnt.hxx>
34 #include <gp_Vec.hxx>
35 #include <Precision.hxx>
36 #include <Prs3d_Drawer.hxx>
37 #include <Prs3d_LineAspect.hxx>
38 #include <Prs3d_Presentation.hxx>
39 #include <Select3D_SensitiveCurve.hxx>
40 #include <Select3D_SensitiveSegment.hxx>
41 #include <SelectMgr_EntityOwner.hxx>
42 #include <SelectMgr_Selection.hxx>
43 #include <Standard_NotImplemented.hxx>
44 #include <Standard_Type.hxx>
45 #include <TCollection_ExtendedString.hxx>
46 #include <TColStd_ListIteratorOfListOfTransient.hxx>
47 #include <TopAbs.hxx>
48 #include <TopExp.hxx>
49 #include <TopoDS.hxx>
50 #include <TopoDS_Edge.hxx>
51 #include <TopoDS_Shape.hxx>
52 #include <TopoDS_Vertex.hxx>
53 #include <TopoDS_Wire.hxx>
54 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
55 #include <TopTools_ListIteratorOfListOfShape.hxx>
56
57 IMPLEMENT_STANDARD_RTTIEXT(AIS_IdenticRelation,AIS_Relation)
58
59 // jfa 15/10/2000
60 static Standard_Real Modulo2PI(const Standard_Real ANGLE)
61 {
62   if ( ANGLE < 0 )          return Modulo2PI(ANGLE + 2*M_PI);
63   else if ( ANGLE >= 2*M_PI ) return Modulo2PI(ANGLE - 2*M_PI);
64   return ANGLE;
65 }
66
67 static Standard_Boolean IsEqual2PI(const Standard_Real angle1,
68                                    const Standard_Real angle2, const Standard_Real precision)
69 {
70   Standard_Real diff = Abs(angle1-angle2);
71   if ( diff < precision )                return Standard_True;
72   else if ( Abs(diff-2*M_PI) < precision ) return Standard_True;
73   return Standard_False;
74 }
75 // jfa 15/10/2000 end
76
77 //=======================================================================
78 //function : AIS_Sort
79 //purpose  : sort an array of parameters <tab1> in increasing order
80 //           updates <tab2> and <tab3> according to <tab1>
81 //=======================================================================
82 static void AIS_Sort(Standard_Real tab1[4],
83                      gp_Pnt tab2[4],
84                      Standard_Integer tab3[4])
85 {
86   Standard_Boolean found = Standard_True;
87   Standard_Real cur; gp_Pnt cur1; Standard_Integer cur2;
88   
89   while (found) {
90     found = Standard_False;
91     for (Standard_Integer i=0; i< 3; i++) {
92       if (tab1[i+1] < tab1[i]) {
93         found = Standard_True;
94         cur = tab1[i]; cur1 = tab2[i]; cur2 = tab3[i];
95         tab1[i] = tab1[i+1]; tab2[i] = tab2[i+1]; tab3[i] = tab3[i+1]; 
96         tab1[i+1] = cur; tab2[i+1] = cur1; tab3[i+1] = cur2; 
97       }
98     }
99   }
100 }
101
102 //=======================================================================
103 //function : ConnectedEdges
104 //purpose  : 
105 //=======================================================================
106 static Standard_Boolean ConnectedEdges(const TopoDS_Wire& WIRE,
107                                        const TopoDS_Vertex& V, 
108                                        TopoDS_Edge& E1, 
109                                        TopoDS_Edge& E2)
110 {
111   TopTools_IndexedDataMapOfShapeListOfShape  vertexMap;
112   TopExp::MapShapesAndAncestors (WIRE,TopAbs_VERTEX,TopAbs_EDGE,vertexMap);
113   
114   Standard_Boolean found(Standard_False);
115   TopoDS_Vertex theVertex;
116   for (Standard_Integer i=1; i<=vertexMap.Extent() && !found; i++) {
117     if (vertexMap.FindKey(i).IsSame(V)) {
118       theVertex = TopoDS::Vertex(vertexMap.FindKey(i));
119       found = Standard_True;
120     }
121   }
122   if (!found) {
123     E1.Nullify();
124     E2.Nullify();
125     return Standard_False;
126   }
127   
128   TopTools_ListIteratorOfListOfShape iterator(vertexMap.FindFromKey(theVertex));
129   if (iterator.More()) {
130     E1 = TopoDS::Edge(iterator.Value());
131     iterator.Next();
132   }
133   else {
134     E1.Nullify();
135     return Standard_False;
136   }
137   
138   if (iterator.More()) {
139     E2 = TopoDS::Edge(iterator.Value());
140     iterator.Next();
141   }
142   else {
143     E2.Nullify();
144     return Standard_False;
145   }
146   
147   if (iterator.More()) {
148     E1.Nullify();
149     E2.Nullify();
150     return Standard_False;
151   }
152   return Standard_True;
153 }
154
155 // jfa 16/10/2000
156 //=======================================================================
157 //function : ComputeAttach
158 //purpose  : Compute a point on the arc of <thecirc>
159 //             between <aFAttach> and <aSAttach>
160 //             corresponding to <aPosition>
161 //           Returns result into <aPosition>
162 // Note    : This function is to be used only in the case of circles.
163 //           The <aPosition> parameter is in/out.
164 //=======================================================================
165 static Standard_Boolean ComputeAttach(const gp_Circ& thecirc,
166                                       const gp_Pnt& aFAttach,
167                                       const gp_Pnt& aSAttach,
168                                       gp_Pnt& aPosition)
169 {
170   gp_Pnt curpos = aPosition;
171
172   // Case of confusion between the current position and the center 
173   // of the circle -> we move the current position
174   Standard_Real confusion (Precision::Confusion());
175   gp_Pnt aCenter = thecirc.Location();
176   if ( aCenter.Distance(curpos) <= confusion )
177     {
178       gp_Vec vprec(aCenter, aFAttach);
179       vprec.Normalize();
180       curpos.Translate(vprec*1e-5);
181     }
182   
183   Standard_Real pcurpos  = ElCLib::Parameter(thecirc,curpos);
184   Standard_Real pFAttach = ElCLib::Parameter(thecirc,aFAttach);
185   Standard_Real pSAttach = ElCLib::Parameter(thecirc,aSAttach);
186
187   Standard_Real pSAttachM = pSAttach;
188   Standard_Real deltap = pSAttachM - pFAttach;
189   if ( deltap < 0 )
190     {
191       deltap += 2 * M_PI;
192       pSAttachM += 2 * M_PI;
193     }
194   pSAttachM -= pFAttach;
195
196   Standard_Real pmiddleout = pSAttachM/2.0 + M_PI;
197
198   Standard_Real pcurpos1 = pcurpos;
199   // define where curpos lays
200   if ( pcurpos1 < pFAttach )
201     {
202       pcurpos1 = pcurpos1 + 2 * M_PI - pFAttach;
203       if ( pcurpos1 > pSAttachM ) // out
204         {
205           if ( pcurpos1 > pmiddleout ) pcurpos = pFAttach;
206           else pcurpos = pSAttach;
207         }
208     }
209   else if ( pcurpos1 > (pFAttach + deltap) ) // out
210     {
211       pcurpos1 -= pFAttach;
212       if ( pcurpos1 > pmiddleout ) pcurpos = pFAttach;
213       else pcurpos = pSAttach;
214     }
215
216   aPosition = ElCLib::Value(pcurpos,thecirc);
217   return Standard_True;
218 }
219
220 //=======================================================================
221 //function : ComputeAttach
222 //purpose  : Compute a point on the arc of ellipse <theEll>
223 //             between <aFAttach> and <aSAttach>
224 //             corresponding to <aPosition>
225 //           Returns result into <aPosition>
226 // Note    : This function is to be used only in the case of ellipses.
227 //           The <aPosition> parameter is in/out.
228 //=======================================================================
229 static Standard_Boolean ComputeAttach(const gp_Elips& theEll,
230                                       const gp_Pnt& aFAttach,
231                                       const gp_Pnt& aSAttach,
232                                       gp_Pnt& aPosition)
233 {
234   gp_Pnt curpos = aPosition;
235
236   // Case of confusion between the current position and the center 
237   // of the circle -> we move the current position
238   Standard_Real confusion (Precision::Confusion());
239   gp_Pnt aCenter = theEll.Location();
240   if ( aCenter.Distance(curpos) <= confusion )
241     {
242       gp_Vec vprec(aCenter, aFAttach);
243       vprec.Normalize();
244       curpos.Translate(vprec*1e-5);
245     }
246   
247 // for ellipses it's not good  Standard_Real pcurpos  = ElCLib::Parameter(theEll,curpos);
248   Handle(Geom_Ellipse) theEllg = new Geom_Ellipse(theEll);
249   GeomAPI_ProjectPointOnCurve aProj (curpos, theEllg);
250   Standard_Real pcurpos  = aProj.LowerDistanceParameter();
251
252   Standard_Real pFAttach = ElCLib::Parameter(theEll,aFAttach);
253   Standard_Real pSAttach = ElCLib::Parameter(theEll,aSAttach);
254
255   Standard_Real pSAttachM = pSAttach;
256   Standard_Real deltap = pSAttachM - pFAttach;
257   if ( deltap < 0 )
258     {
259       deltap += 2 * M_PI;
260       pSAttachM += 2 * M_PI;
261     }
262   pSAttachM -= pFAttach;
263
264   Standard_Real pmiddleout = pSAttachM/2.0 + M_PI;
265
266   Standard_Real pcurpos1 = pcurpos;
267   // define where curpos lays
268   if ( pcurpos1 < pFAttach )
269     {
270       pcurpos1 = pcurpos1 + 2 * M_PI - pFAttach;
271       if ( pcurpos1 > pSAttachM ) // out
272         {
273           if ( pcurpos1 > pmiddleout ) pcurpos = pFAttach;
274           else pcurpos = pSAttach;
275         }
276     }
277   else if ( pcurpos1 > (pFAttach + deltap) ) // out
278     {
279       pcurpos1 -= pFAttach;
280       if ( pcurpos1 > pmiddleout ) pcurpos = pFAttach;
281       else pcurpos = pSAttach;
282     }
283
284   aPosition = ElCLib::Value(pcurpos,theEll);
285   return Standard_True;
286 }
287 // jfa 16/10/2000 end
288
289 //=======================================================================
290 //function : AIS_IdenticRelation
291 //purpose  : 
292 //=======================================================================
293 AIS_IdenticRelation::AIS_IdenticRelation(const TopoDS_Shape& FirstShape, 
294                                          const TopoDS_Shape& SecondShape, 
295                                          const Handle(Geom_Plane)& aPlane)
296   :isCircle(Standard_False)
297 {
298   myFShape = FirstShape;
299   mySShape = SecondShape;
300   myPlane  = aPlane;
301 }
302
303 //=======================================================================
304 //function : Compute
305 //purpose  : 
306 //=======================================================================
307 void AIS_IdenticRelation::Compute(const Handle(PrsMgr_PresentationManager3d)&, 
308                                   const Handle(Prs3d_Presentation)& aprs, 
309                                   const Standard_Integer)
310 {
311   switch ( myFShape.ShapeType() ) {
312     
313   case TopAbs_VERTEX:
314     {
315       switch ( mySShape.ShapeType() ) {
316       case TopAbs_VERTEX:
317         {
318           ComputeTwoVerticesPresentation(aprs);
319         }
320       break;
321       case TopAbs_EDGE:
322         {
323           ComputeOneEdgeOVertexPresentation(aprs);
324         }
325       break;
326       default:
327         break;
328       }
329     }
330     break;
331     
332   case TopAbs_EDGE:
333     {
334       switch ( mySShape.ShapeType() ) {
335       case TopAbs_VERTEX:
336         {
337           ComputeOneEdgeOVertexPresentation(aprs);
338         }
339       break;
340       case TopAbs_EDGE:
341         {
342           ComputeTwoEdgesPresentation(aprs);      
343         }
344       break;
345       default:
346         break;
347       }
348     }
349   break;
350   default: break;
351   }
352 }
353
354 //=======================================================================
355 //function : ComputeSelection
356 //purpose  : function used to compute the selection associated to the 
357 //           "identic" presentation
358 // note    : if we are in the case of lines, we create a segment between
359 //           myFAttach and mySAttach. In the case of Circles, we create
360 //           an arc of circle between the sames points. We Add a segment
361 //           to link Position to its projection on the curve described
362 //           before.
363 //=======================================================================
364
365 void AIS_IdenticRelation::ComputeSelection(const Handle(SelectMgr_Selection)& aSelection, 
366                                            const Standard_Integer)
367 {
368   Handle(SelectMgr_EntityOwner) own = new SelectMgr_EntityOwner(this,7);
369
370   Handle(Select3D_SensitiveSegment) seg;
371   // attachement point of the segment linking position to the curve
372   gp_Pnt attach; 
373   Standard_Real confusion (Precision::Confusion());
374     
375   if ( myFAttach.IsEqual(mySAttach, confusion) )
376     {
377       attach = myFAttach;
378     }
379   else
380     {    
381 // jfa 24/10/2000
382       if ( myFShape.ShapeType() == TopAbs_EDGE )
383         {
384           Handle(Geom_Curve) curv1,curv2;
385           gp_Pnt firstp1,lastp1,firstp2,lastp2;
386           Standard_Boolean isInfinite1,isInfinite2;
387           Handle(Geom_Curve) extCurv;
388           if ( !AIS::ComputeGeometry(TopoDS::Edge(myFShape),TopoDS::Edge(mySShape),
389                                      myExtShape,curv1,curv2,
390                                      firstp1,lastp1,firstp2,lastp2,
391                                      extCurv,isInfinite1,isInfinite2,myPlane) ) return;
392
393           if ( isCircle ) // case of Circles
394             {
395               Handle(Geom_Circle) thecirc = Handle(Geom_Circle)::DownCast (curv1);
396               Standard_Real udeb = ElCLib::Parameter(thecirc->Circ(),myFAttach);
397               Standard_Real ufin = ElCLib::Parameter(thecirc->Circ(),mySAttach);
398               Handle(Geom_Curve) thecu = new Geom_TrimmedCurve(thecirc,udeb,ufin);
399       
400               Handle(Select3D_SensitiveCurve) scurv = new Select3D_SensitiveCurve(own, thecu);
401               aSelection->Add(scurv);
402       
403               attach = myPosition;
404               ComputeAttach(thecirc->Circ(),myFAttach,mySAttach,attach);
405             }
406           else if ( curv1->IsInstance(STANDARD_TYPE(Geom_Ellipse)) ) // case of ellipses
407             {
408               Handle(Geom_Ellipse) theEll = Handle(Geom_Ellipse)::DownCast (curv1);
409
410               Standard_Real udeb = ElCLib::Parameter(theEll->Elips(),myFAttach);
411               Standard_Real ufin = ElCLib::Parameter(theEll->Elips(),mySAttach);
412               Handle(Geom_Curve) thecu = new Geom_TrimmedCurve(theEll,udeb,ufin);
413       
414               Handle(Select3D_SensitiveCurve) scurv = new Select3D_SensitiveCurve(own, thecu);
415               aSelection->Add(scurv);
416       
417               attach = myPosition;
418               ComputeAttach(theEll->Elips(),myFAttach,mySAttach,attach);
419             }
420           else if ( curv1->IsInstance(STANDARD_TYPE(Geom_Line)) ) // case of Lines
421             {
422               seg = new Select3D_SensitiveSegment(own, myFAttach, mySAttach);
423               aSelection->Add(seg);
424               
425               //attach = projection of Position() on the curve;
426               gp_Vec v1 (myFAttach, mySAttach);
427               gp_Vec v2 (myFAttach, myPosition);
428               if ( v1.IsParallel(v2, Precision::Angular()) )
429                 {
430                   attach = mySAttach;
431                 }
432               else
433                 {
434                   gp_Lin ll (myFAttach, gp_Dir(v1));
435                   attach = ElCLib::Value(ElCLib::Parameter(ll,myPosition), ll);
436                 }
437             }
438           else return;
439         }
440 //      else if ( myFShape.ShapeType() == TopAbs_VERTEX )
441 //      {
442 //      }
443 // jfa 24/10/2000 end
444     }
445
446   // Creation of the segment linking the attachement point with the
447   // position
448   if ( !attach.IsEqual(myPosition, confusion) )
449     {
450       seg = new Select3D_SensitiveSegment(own, attach, myPosition);
451       aSelection->Add(seg);
452     }
453 }
454
455 //=======================================================================
456 //function : ComputeTwoEdgesPresentation
457 //purpose  : 
458 //=======================================================================
459 void AIS_IdenticRelation::ComputeTwoEdgesPresentation(const Handle(Prs3d_Presentation)& aPrs)
460 {
461   Handle(Geom_Curve) curv1,curv2;
462   gp_Pnt firstp1,lastp1,firstp2,lastp2;
463   Standard_Boolean isInfinite1,isInfinite2;
464
465   Handle(Geom_Curve) extCurv;
466   if (!AIS::ComputeGeometry(TopoDS::Edge(myFShape),
467                             TopoDS::Edge(mySShape),
468                             myExtShape,
469                             curv1,
470                             curv2,
471                             firstp1,
472                             lastp1,
473                             firstp2,
474                             lastp2,
475                             extCurv,
476                             isInfinite1,isInfinite2,
477                             myPlane))
478     return;
479   aPrs->SetInfiniteState((isInfinite1 || isInfinite2) && myExtShape != 0);
480
481   // Treatement of the case of lines
482   if ( curv1->IsInstance(STANDARD_TYPE(Geom_Line)) && curv2->IsInstance(STANDARD_TYPE(Geom_Line)) ) {
483     // we take the line curv1 like support
484     Handle(Geom_Line) thelin;
485     if (isInfinite1 && !isInfinite2) thelin = Handle(Geom_Line)::DownCast (curv2);
486     else if (!isInfinite1 && isInfinite2) thelin = Handle(Geom_Line)::DownCast (curv1);
487     else thelin = Handle(Geom_Line)::DownCast (curv1);
488     ComputeTwoLinesPresentation(aPrs, thelin, firstp1, lastp1, firstp2, lastp2, isInfinite1, isInfinite2);
489   }
490
491   //  Treatement of the case of circles
492   else if ( curv1->IsInstance(STANDARD_TYPE(Geom_Circle)) && curv2->IsInstance(STANDARD_TYPE(Geom_Circle)) ) {
493     //gp_Pnt curpos;
494     isCircle = Standard_True; // useful for ComputeSelection
495     Handle(Geom_Circle) thecirc (Handle(Geom_Circle)::DownCast (curv1));
496     ComputeTwoCirclesPresentation(aPrs, thecirc, firstp1, lastp1, firstp2, lastp2);
497   }
498
499   // jfa 10/10/2000
500   //  Treatement of the case of ellipses
501   else if ( curv1->IsInstance(STANDARD_TYPE(Geom_Ellipse)) && curv2->IsInstance(STANDARD_TYPE(Geom_Ellipse)) )
502       {
503         Handle(Geom_Ellipse) theEll (Handle(Geom_Ellipse)::DownCast (curv1));
504         ComputeTwoEllipsesPresentation(aPrs, theEll, firstp1, lastp1, firstp2, lastp2);
505       }
506   // jfa 10/10/2000 end
507   else
508     return;
509
510  // Calculate presentation of projected edges
511  if ( (myExtShape != 0) &&  !extCurv.IsNull()) {
512    if (myExtShape == 1 )
513      ComputeProjEdgePresentation(aPrs, TopoDS::Edge(myFShape), curv1, firstp1, lastp1);
514    else
515      ComputeProjEdgePresentation(aPrs, TopoDS::Edge(mySShape), curv2, firstp2, lastp2);
516  }
517 }
518
519 //=======================================================================
520 //function : ComputeTwoLinesPresentation
521 //purpose  : Compute the presentation of the 'identic' constraint
522 //           between two lines ( which are equal)
523 //input    : <thelin> : the 
524 //           <firstp1>: first extremity of the 1st curve of the constraint
525 //           <lastp1> : last extremity of the 1st curve of the constraint
526 //           <firstp2>: first extremity of the 2nd curve of the constraint
527 //           <lastp2> :last extremity of the 2nd curve of the constraint
528 //=======================================================================
529 void AIS_IdenticRelation::ComputeTwoLinesPresentation(const Handle(Prs3d_Presentation)& aPrs, 
530                                                       const Handle(Geom_Line)& thelin,
531                                                       gp_Pnt& firstp1,
532                                                       gp_Pnt& lastp1,
533                                                       gp_Pnt& firstp2,
534                                                       gp_Pnt& lastp2,
535                                                       const Standard_Boolean isInfinite1,
536                                                       const Standard_Boolean isInfinite2)
537 {
538   if (isInfinite1 && isInfinite2) {
539     if ( myAutomaticPosition ) {
540       myFAttach = mySAttach = thelin->Lin().Location();
541       gp_Pnt curpos;
542       gp_Pln pln(myPlane->Pln());
543       gp_Dir dir(pln.XAxis().Direction());
544       gp_Vec transvec = gp_Vec(dir)*myArrowSize;
545       curpos = myFAttach.Translated(transvec);
546       myPosition = curpos;
547       myAutomaticPosition = Standard_True;
548     }
549     else {
550       myFAttach = mySAttach = ElCLib::Value(ElCLib::Parameter(thelin->Lin(),myPosition),thelin->Lin());            
551     }
552     TCollection_ExtendedString vals(" ==");
553     DsgPrs_IdenticPresentation::Add(aPrs,
554                                     myDrawer,
555                                     vals,
556                                     myFAttach,
557                                     myPosition);    
558   }
559   else {
560     // Computation of the parameters of the 4 points on the line <thelin>
561     Standard_Real pf1, pf2, pl1, pl2;    
562
563     pf1 = ElCLib::Parameter(thelin->Lin(), firstp1);
564     pl1 = ElCLib::Parameter(thelin->Lin(), lastp1);
565
566     pf2 = ElCLib::Parameter(thelin->Lin(), firstp2);
567     pl2 = ElCLib::Parameter(thelin->Lin(), lastp2);
568
569     if (isInfinite1) {
570       pf1 = pf2;
571       pl1 = pl2;
572       firstp1 = firstp2;
573       lastp1 = lastp2;
574     }
575     else if (isInfinite2) {
576       pf2 = pf1;
577       pl2 = pl1;
578       firstp2 = firstp1;
579       lastp2 = lastp1;
580     }
581
582     Standard_Real tabRang1[4];      // array taht contains the parameters of the 4 points
583     // ordered by increasing abscisses.
584
585     gp_Pnt tabRang2[4];             // array containing the points corresponding to the
586     // parameters in tabRang1
587
588     Standard_Integer tabRang3[4];   // array containing the number of the curve( 1 or 2)
589     // of which belongs each point of tabRang2
590
591     // Filling of the arrays
592     tabRang1[0] = pf1; tabRang2[0] = firstp1; tabRang3[0] = 1;
593     tabRang1[1] = pf2; tabRang2[1] = firstp2; tabRang3[1] = 2;
594     tabRang1[2] = pl1; tabRang2[2] = lastp1;  tabRang3[2] = 1;
595     tabRang1[3] = pl2; tabRang2[3] = lastp2;  tabRang3[3] = 2;
596
597   // Sort of the array of parameters (tabRang1)
598     AIS_Sort(tabRang1, tabRang2, tabRang3);
599
600     // Computation of myFAttach and mySAttach according to the
601     // position of the 2 linear edges
602     gp_Pnt curpos;
603     gp_Pnt middle;
604   
605     if ( (tabRang1[0] == tabRang1[1]) && (tabRang1[2] == tabRang1[3]) ) {
606       middle.SetXYZ((tabRang2[1].XYZ() + tabRang2[2].XYZ())/2. );
607       Standard_Real pmiddle = (tabRang1[1] + tabRang1[2]) / 2.;
608       Standard_Real delta = (tabRang1[3] - tabRang1[0])/ 5.;
609       myFAttach = ElCLib::Value(pmiddle-delta, thelin->Lin());
610       mySAttach = ElCLib::Value(pmiddle+delta, thelin->Lin());
611     }
612   
613     else if ( tabRang1[1] == tabRang1[2] ) {
614       middle = tabRang2[1];
615       Standard_Real delta1 = tabRang1[1] - tabRang1[0];
616       Standard_Real delta2 = tabRang1[3] - tabRang1[2];
617       if ( delta1 > delta2 ) delta1 = delta2;
618       myFAttach = ElCLib::Value(tabRang1[1]-delta1/2., thelin->Lin());
619       mySAttach = ElCLib::Value(tabRang1[1]+delta1/2., thelin->Lin());
620     }
621   
622     // Case of 2 disconnected segments -> the symbol completes the gap 
623     //                                    between the 2 edges
624     //--------------------------------
625     else if ( (tabRang3[0] == tabRang3[1]) && (tabRang1[1] != tabRang1[2])) {
626       middle.SetXYZ((tabRang2[1].XYZ() + tabRang2[2].XYZ())/2. );
627       myFAttach = tabRang2[1];
628       mySAttach = tabRang2[2];
629     }
630     else if ( (tabRang3[0] != tabRang3[1]) 
631               && (tabRang3[1] != tabRang3[2])    // Intersection
632               && (tabRang1[1] != tabRang1[2]) ) { 
633       middle.SetXYZ((tabRang2[1].XYZ() + tabRang2[2].XYZ())/2. );
634       myFAttach = tabRang2[1];
635       mySAttach = tabRang2[2];
636     }
637     else {                                     // Inclusion
638       myFAttach.SetXYZ((tabRang2[0].XYZ() + tabRang2[1].XYZ())/2. );
639       mySAttach.SetXYZ((tabRang2[1].XYZ() + tabRang2[2].XYZ())/2. );
640       middle.SetXYZ( (myFAttach.XYZ() + mySAttach.XYZ() )/2.);
641     }
642   
643
644     if ( myAutomaticPosition ) {
645     
646       gp_Vec vtrans(myFAttach, mySAttach);
647       vtrans.Normalize();
648       vtrans.Cross(gp_Vec(myPlane->Pln().Axis().Direction()));
649       vtrans *= ComputeSegSize();
650       curpos = middle.Translated(vtrans);
651       myPosition = curpos;
652       myAutomaticPosition = Standard_True;
653     }
654
655     else {
656
657       curpos = myPosition;
658       Standard_Real pcurpos = ElCLib::Parameter(thelin->Lin() ,curpos);
659       Standard_Real dist = thelin->Lin().Distance(curpos);
660       gp_Pnt proj = ElCLib::Value( pcurpos, thelin->Lin());
661       gp_Vec  trans;
662       Standard_Real confusion(Precision::Confusion());
663       if ( dist >= confusion ) {
664         trans = gp_Vec(proj, curpos);
665         trans.Normalize();
666       }
667       Standard_Real pf = ElCLib::Parameter(thelin->Lin() ,myFAttach);
668       Standard_Real pl = ElCLib::Parameter(thelin->Lin() ,mySAttach);
669       if ( pcurpos <= pf ) {
670         pcurpos = pf + 1e-5;
671         curpos = ElCLib::Value( pcurpos, thelin->Lin());
672         if ( dist >= confusion ) curpos.Translate(trans*dist);
673       }
674       else if ( pcurpos >= pl ) {
675         pcurpos = pl - 1e-5;
676         curpos = ElCLib::Value( pcurpos, thelin->Lin());
677         if ( dist >= confusion ) curpos.Translate(trans*dist);
678       }
679       SetPosition(curpos);
680     }
681
682     // Display of the presentation
683     TCollection_ExtendedString vals(" ==");
684     DsgPrs_IdenticPresentation::Add(aPrs,
685                                     myDrawer,
686                                     vals,
687                                     myFAttach,
688                                     mySAttach,
689                                     curpos);
690   }
691 }
692
693 // jfa 17/10/2000
694 //=======================================================================
695 //function : ComputeTwoCirclesPresentation
696 //purpose  : Compute the presentation of the 'identic' constraint
697 //           between two circles ( which are equal)
698 //input    : <thecirc>: the circle
699 //           <firstp1>: first extremity of the 1st curve of the constraint
700 //           <lastp1> : last extremity of the 1st curve of the constraint
701 //           <firstp2>: first extremity of the 2nd curve of the constraint
702 //           <lastp2> :last extremity of the 2nd curve of the constraint
703 //=======================================================================
704 void AIS_IdenticRelation::ComputeTwoCirclesPresentation(const Handle(Prs3d_Presentation)& aPrs,
705                                                         const Handle(Geom_Circle)& thecirc,
706                                                         const gp_Pnt& firstp1,
707                                                         const gp_Pnt& lastp1,
708                                                         const gp_Pnt& firstp2,
709                                                         const gp_Pnt& lastp2)
710 {
711   Standard_Real confusion (Precision::Confusion());
712
713   // Searching of complete circles
714   Standard_Boolean circ1complete = (firstp1.IsEqual(lastp1, confusion));
715   Standard_Boolean circ2complete = (firstp2.IsEqual(lastp2, confusion));
716     
717   myCenter = thecirc->Location();
718   Standard_Real aSegSize = thecirc->Radius()/5.0;
719   Standard_Real rad = M_PI / 5.0;
720     
721   // I. Case of 2 complete circles
722   if ( circ1complete && circ2complete )
723     {
724       if (myAutomaticPosition)
725         {
726           Standard_Real pfirst1 = ElCLib::Parameter(thecirc->Circ(), firstp1);
727           myFAttach = ElCLib::Value(Modulo2PI(pfirst1-rad), thecirc->Circ());
728           mySAttach = ElCLib::Value(Modulo2PI(pfirst1+rad), thecirc->Circ());
729
730           gp_Pnt curpos = ElCLib::Value(pfirst1,thecirc->Circ());
731           gp_Vec vtrans(myCenter, curpos);
732           vtrans.Normalize();
733           vtrans *= aSegSize;
734           curpos.Translate(vtrans);
735           myPosition = curpos;
736         }
737       else ComputeNotAutoCircPresentation(thecirc);
738     }
739
740   // II. Case of one complete circle and one arc
741   else if ( (circ1complete && !circ2complete) || (!circ1complete && circ2complete) )
742     {
743       gp_Pnt firstp, lastp;
744       if ( circ1complete && !circ2complete)
745         {
746           firstp = firstp2;
747           lastp  = lastp2;
748         }
749       else
750         {
751           firstp = firstp1;
752           lastp  = lastp1;
753         }
754
755       if (myAutomaticPosition)
756         {
757           ComputeAutoArcPresentation(thecirc, firstp, lastp);
758         }
759       else
760         {
761           ComputeNotAutoArcPresentation(thecirc, firstp, lastp);
762         }
763     }
764
765   // III and IV. Case of two arcs
766   else if ( !circ1complete && !circ2complete )
767     {
768       // We project all the points on the circle
769       Standard_Real pf1, pf2, pl1, pl2;
770       pf1 = ElCLib::Parameter(thecirc->Circ(), firstp1);
771       pf2 = ElCLib::Parameter(thecirc->Circ(), firstp2);
772       pl1 = ElCLib::Parameter(thecirc->Circ(), lastp1);
773       pl2 = ElCLib::Parameter(thecirc->Circ(), lastp2);
774
775       // III. Arcs with common ends
776       // III.1. First of one and last of another
777       if ( IsEqual2PI(pl1,pf2,confusion) || IsEqual2PI(pf1,pl2,confusion) )
778         {
779           gp_Pnt curpos(0.,0.,0.);
780           Standard_Real att=0.;
781           if ( IsEqual2PI(pl1,pf2,confusion) )
782             {
783               att = pl1;
784               curpos = lastp1;
785             }
786           else if ( IsEqual2PI(pf1,pl2,confusion) )
787             {
788               att = pf1;
789               curpos = firstp1;
790             }
791           Standard_Real maxrad = Min(Modulo2PI(pl1 - pf1),Modulo2PI(pl2 - pf2))*3/4;
792           if ( rad > maxrad ) rad = maxrad;
793           Standard_Real pFAttach = Modulo2PI(att - rad);
794           Standard_Real pSAttach = Modulo2PI(att + rad);
795           myFAttach = ElCLib::Value(pFAttach, thecirc->Circ());
796           mySAttach = ElCLib::Value(pSAttach, thecirc->Circ());
797           if ( myAutomaticPosition )
798             {
799               gp_Vec vtrans(myCenter,curpos);
800               vtrans.Normalize();
801               vtrans *= aSegSize;
802               curpos.Translate(vtrans);
803               myPosition = curpos;
804             }
805         }
806       // III.2. Two first or two last
807       else if ( IsEqual2PI(pf1,pf2,confusion) || IsEqual2PI(pl1,pl2,confusion) )
808         {
809           Standard_Real l1 = Modulo2PI(pl1 - pf1);
810           Standard_Real l2 = Modulo2PI(pl2 - pf2);
811           gp_Pnt firstp,lastp;
812           if ( l1 < l2 )
813             {
814               firstp = firstp1;
815               lastp = lastp1;
816             }
817           else
818             {
819               firstp = firstp2;
820               lastp = lastp2;
821             }
822
823           if ( myAutomaticPosition )
824             {
825               ComputeAutoArcPresentation(thecirc, firstp, lastp);
826             }
827           else
828             {
829               ComputeNotAutoArcPresentation(thecirc, firstp, lastp);
830             }
831         }
832       // IV. All others arcs (without common ends)
833       else
834         {
835           // order the parameters; first will be pf1
836           Standard_Real pl1m = Modulo2PI(pl1 - pf1);
837           Standard_Real pf2m = Modulo2PI(pf2 - pf1);
838           Standard_Real pl2m = Modulo2PI(pl2 - pf1);
839
840           Standard_Boolean case1 = Standard_False;
841           // 1 - not intersecting arcs
842           // 2 - intersecting arcs, but one doesn't contain another
843           // 3a - first arc contains the second one
844           // 3b - second arc contains the first one
845           // 4 - two intersections
846
847           gp_Pnt firstp, lastp;
848
849           if ( pl1m < pf2m ) // 1 or 2b or 3b
850             {
851               if ( pl1m < pl2m ) // 1 or 3b
852                 {
853                   if ( pl2m < pf2m ) // 3b
854                     {
855                       firstp = firstp1;
856                       lastp  = lastp1;
857                     }
858                   else // 1
859                     {
860                       case1 = Standard_True;
861                       Standard_Real deltap1 = Modulo2PI(pf1 - pl2);
862                       Standard_Real deltap2 = Modulo2PI(pf2 - pl1);
863                       if ( ((deltap1 < deltap2) && (deltap1 < 2*rad)) ||
864                            ((deltap2 < deltap1) && (deltap2 > 2*rad)) ) // deltap2
865                         {
866                           firstp = lastp1;
867                           lastp  = firstp2;
868                         }
869                       else // deltap1
870                         {
871                           firstp = lastp2;
872                           lastp  = firstp1;
873                         }
874                     }
875                 }
876               else // 2b
877                 {
878                   firstp = firstp1;
879                   lastp  = lastp2;
880                 }
881             }
882           else // 2a or 3a or 4
883             {
884               if ( pl1m < pl2m ) // 2a
885                 {
886                   firstp = firstp2;
887                   lastp  = lastp1;
888                 }
889               else // 3a or 4
890                 {
891                   if ( pl2m > pf2m ) // 3a
892                     {
893                       firstp = firstp2;
894                       lastp  = lastp2;
895                     }
896                   else // 4
897                     {
898                       Standard_Real deltap1 = Modulo2PI(pl1 - pf2);
899                       Standard_Real deltap2 = Modulo2PI(pl2 - pf1);
900                       if ( ((deltap1 < deltap2) && (deltap1 < 2*rad)) ||
901                            ((deltap2 < deltap1) && (deltap2 > 2*rad)) ) // deltap2
902                         {
903                           firstp = firstp1;
904                           lastp  = lastp2;
905                         }
906                       else // deltap1
907                         {
908                           firstp = firstp2;
909                           lastp  = lastp1;
910                         }
911                     }
912                 }
913             }
914
915           if ( myAutomaticPosition )
916             {
917               ComputeAutoArcPresentation(thecirc,firstp,lastp,case1);
918             }
919           else
920             {
921               if ( case1 )
922                 {
923                   myFAttach = firstp;
924                   mySAttach = lastp;
925                 }
926               else ComputeNotAutoArcPresentation(thecirc, firstp, lastp);
927             }
928         }
929     }
930
931   // Display of the presentation
932   TCollection_ExtendedString vals(" ==");
933   gp_Pnt attach = myPosition;
934   ComputeAttach(thecirc->Circ(),myFAttach,mySAttach,attach);
935   DsgPrs_IdenticPresentation::Add(aPrs,
936                                   myDrawer,
937                                   vals,
938                                   myPlane->Pln().Position().Ax2(),
939                                   myCenter,
940                                   myFAttach,
941                                   mySAttach,
942                                   myPosition,
943                                   attach);
944 }
945
946 //=======================================================================
947 //function : ComputeAutoArcPresentation
948 //purpose  : Compute the presentation of the constraint where we are
949 //           not in the case of dragging.
950 //=======================================================================
951 void AIS_IdenticRelation::ComputeAutoArcPresentation(const Handle(Geom_Circle)& thecirc,
952                                                      const gp_Pnt& firstp,
953                                                      const gp_Pnt& lastp,
954                                                      const Standard_Boolean isstatic)
955 {
956   Standard_Real aSegSize = thecirc->Radius()/5.0;
957   Standard_Real rad = M_PI / 5.0;
958
959   Standard_Real pFA = ElCLib::Parameter(thecirc->Circ(),firstp);
960   Standard_Real pSA = ElCLib::Parameter(thecirc->Circ(),lastp);
961   Standard_Real maxrad = Modulo2PI(pSA - pFA)/2.0;
962   
963   if ( (rad > maxrad) || isstatic ) rad = maxrad;
964   Standard_Real pmiddle = Modulo2PI(pFA + Modulo2PI(pSA - pFA)/2.0);
965   
966   myFAttach = ElCLib::Value(Modulo2PI(pmiddle - rad),thecirc->Circ());
967   mySAttach = ElCLib::Value(Modulo2PI(pmiddle + rad),thecirc->Circ());
968   
969   gp_Pnt curpos = ElCLib::Value(pmiddle,thecirc->Circ());
970   gp_Vec vtrans(myCenter, curpos);
971   vtrans.Normalize();
972   vtrans *= aSegSize;
973   myPosition = curpos.Translated(vtrans);
974 }
975
976 //=======================================================================
977 //function : ComputeNotAutoCircPresentation
978 //purpose  : Compute the presentation of the constraint where we are
979 //           in the case of dragging.
980 // Note    : This function is to be used only in the case of full circles.
981 //           The symbol of the constraint moves together with arc
982 //           representing the constraint around all the circle.
983 //=======================================================================
984 void AIS_IdenticRelation::ComputeNotAutoCircPresentation(const Handle(Geom_Circle)& thecirc)
985 {
986   gp_Pnt curpos = myPosition;
987
988   Handle(Geom_Circle) cirNotAuto = new Geom_Circle(thecirc->Circ());
989   
990   // Case of confusion between the current position and the center 
991   // of the circle -> we move the current position
992   Standard_Real confusion (Precision::Confusion());
993   if ( myCenter.Distance(curpos) <= confusion )
994     {
995       gp_Vec vprec(myCenter, myFAttach);
996       vprec.Normalize();
997       curpos.Translate(vprec*1e-5);
998     }
999   
1000   Standard_Real rad = M_PI / 5.0;
1001   Standard_Real pcurpos = ElCLib::Parameter(cirNotAuto->Circ(),curpos);
1002   Standard_Real pFAttach = pcurpos - rad;
1003   Standard_Real pSAttach = pcurpos + rad;
1004   myFAttach = ElCLib::Value(pFAttach,cirNotAuto->Circ());
1005   mySAttach = ElCLib::Value(pSAttach,cirNotAuto->Circ());
1006 }
1007
1008 //=======================================================================
1009 //function : ComputeNotAutoArcPresentation
1010 //purpose  : Compute the presentation of the constraint where we are
1011 //           in the case of dragging.
1012 // Note    : This function is to be used only in the case of circles.
1013 //           The symbol of the constraint moves only between myFAttach
1014 //           and mySAttach.
1015 //=======================================================================
1016 void AIS_IdenticRelation::ComputeNotAutoArcPresentation(const Handle(Geom_Circle)& thecirc,
1017                                                         const gp_Pnt& pntfirst,
1018                                                         const gp_Pnt& pntlast)
1019 {
1020   gp_Pnt curpos = myPosition;
1021
1022   gp_Circ cirNotAuto = thecirc->Circ();
1023
1024   Standard_Real pFPnt = ElCLib::Parameter(cirNotAuto, pntfirst);
1025   Standard_Real pSPnt = ElCLib::Parameter(cirNotAuto, pntlast);
1026   Standard_Real deltap = Modulo2PI(pSPnt - pFPnt)/2.0;
1027
1028   Standard_Real rad = M_PI / 5;
1029   if ( deltap < rad )
1030     {
1031       myFAttach = pntfirst;
1032       mySAttach = pntlast;
1033     }
1034   else
1035     {
1036       gp_Pnt aFPnt = ElCLib::Value(Modulo2PI(pFPnt + rad), cirNotAuto);
1037       gp_Pnt aSPnt = ElCLib::Value(Modulo2PI(pSPnt - rad), cirNotAuto);
1038
1039       ComputeAttach(cirNotAuto,aFPnt,aSPnt,curpos);
1040
1041       Standard_Real pcurpos = ElCLib::Parameter(cirNotAuto,curpos);
1042       myFAttach = ElCLib::Value(pcurpos - rad, cirNotAuto);
1043       mySAttach = ElCLib::Value(pcurpos + rad, cirNotAuto);
1044     }
1045 }
1046 // jfa 17/10/2000 end
1047
1048 // jfa 18/10/2000
1049 //=======================================================================
1050 //function : ComputeTwoEllipsesPresentation
1051 //purpose  : Compute the presentation of the 'identic' constraint
1052 //           between two ellipses (which are equal)
1053 //input    : <theEll>: the ellipse
1054 //           <firstp1>: first extremity of the 1st curve of the constraint
1055 //           <lastp1> : last extremity of the 1st curve of the constraint
1056 //           <firstp2>: first extremity of the 2nd curve of the constraint
1057 //           <lastp2> :last extremity of the 2nd curve of the constraint
1058 //=======================================================================
1059 void AIS_IdenticRelation::ComputeTwoEllipsesPresentation(const Handle(Prs3d_Presentation)& aPrs,
1060                                                          const Handle(Geom_Ellipse)& theEll,
1061                                                          const gp_Pnt& firstp1,
1062                                                          const gp_Pnt& lastp1,
1063                                                          const gp_Pnt& firstp2,
1064                                                          const gp_Pnt& lastp2)
1065 {
1066   Standard_Real confusion (Precision::Confusion());
1067
1068   // Searching of complete ellipses
1069   Standard_Boolean circ1complete = (firstp1.IsEqual(lastp1, confusion));
1070   Standard_Boolean circ2complete = (firstp2.IsEqual(lastp2, confusion));
1071     
1072   myCenter = theEll->Location();
1073   Standard_Real aSegSize = theEll->MajorRadius()/5.0;
1074   Standard_Real rad = M_PI / 5.0;
1075     
1076   // I. Case of 2 complete ellipses
1077   if ( circ1complete && circ2complete )
1078     {
1079       if (myAutomaticPosition)
1080         {
1081           Standard_Real pfirst1 = ElCLib::Parameter(theEll->Elips(), firstp1);
1082           myFAttach = ElCLib::Value(Modulo2PI(pfirst1-rad), theEll->Elips());
1083           mySAttach = ElCLib::Value(Modulo2PI(pfirst1+rad), theEll->Elips());
1084
1085           gp_Pnt curpos = ElCLib::Value(pfirst1,theEll->Elips());
1086           gp_Vec vtrans(myCenter, curpos);
1087           vtrans.Normalize();
1088           vtrans *= aSegSize;
1089           curpos.Translate(vtrans);
1090           myPosition = curpos;
1091         }
1092       else ComputeNotAutoElipsPresentation(theEll);
1093     }
1094
1095   // II. Case of one complete circle and one arc
1096   else if ( (circ1complete && !circ2complete) || (!circ1complete && circ2complete) )
1097     {
1098       gp_Pnt firstp, lastp;
1099       if ( circ1complete && !circ2complete)
1100         {
1101           firstp = firstp2;
1102           lastp  = lastp2;
1103         }
1104       else
1105         {
1106           firstp = firstp1;
1107           lastp  = lastp1;
1108         }
1109
1110       if (myAutomaticPosition)
1111         {
1112           ComputeAutoArcPresentation(theEll, firstp, lastp);
1113         }
1114       else
1115         {
1116           ComputeNotAutoArcPresentation(theEll, firstp, lastp);
1117         }
1118     }
1119
1120   // III and IV. Case of two arcs
1121   else if ( !circ1complete && !circ2complete )
1122     {
1123       // We project all the points on the circle
1124       Standard_Real pf1, pf2, pl1, pl2;
1125       pf1 = ElCLib::Parameter(theEll->Elips(), firstp1);
1126       pf2 = ElCLib::Parameter(theEll->Elips(), firstp2);
1127       pl1 = ElCLib::Parameter(theEll->Elips(), lastp1);
1128       pl2 = ElCLib::Parameter(theEll->Elips(), lastp2);
1129
1130       // III. Arcs with common ends
1131       // III.1. First of one and last of another
1132       if ( IsEqual2PI(pl1,pf2,confusion) || IsEqual2PI(pf1,pl2,confusion) )
1133         {
1134           gp_Pnt curpos;
1135           Standard_Real att=0.;
1136           if ( IsEqual2PI(pl1,pf2,confusion) )
1137             {
1138               att = pl1;
1139               curpos = lastp1;
1140             }
1141           else if ( IsEqual2PI(pf1,pl2,confusion) )
1142             {
1143               att = pf1;
1144               curpos = firstp1;
1145             }
1146           Standard_Real maxrad = Min(Modulo2PI(pl1 - pf1),Modulo2PI(pl2 - pf2))*3/4;
1147           if ( rad > maxrad ) rad = maxrad;
1148           Standard_Real pFAttach = Modulo2PI(att - rad);
1149           Standard_Real pSAttach = Modulo2PI(att + rad);
1150           myFAttach = ElCLib::Value(pFAttach, theEll->Elips());
1151           mySAttach = ElCLib::Value(pSAttach, theEll->Elips());
1152           if ( myAutomaticPosition )
1153             {
1154               gp_Vec vtrans(myCenter,curpos);
1155               vtrans.Normalize();
1156               vtrans *= aSegSize;
1157               curpos.Translate(vtrans);
1158               myPosition = curpos;
1159             }
1160         }
1161       // III.2. Two first or two last
1162       else if ( IsEqual2PI(pf1,pf2,confusion) || IsEqual2PI(pl1,pl2,confusion) )
1163         {
1164           Standard_Real l1 = Modulo2PI(pl1 - pf1);
1165           Standard_Real l2 = Modulo2PI(pl2 - pf2);
1166           gp_Pnt firstp,lastp;
1167           if ( l1 < l2 )
1168             {
1169               firstp = firstp1;
1170               lastp = lastp1;
1171             }
1172           else
1173             {
1174               firstp = firstp2;
1175               lastp = lastp2;
1176             }
1177
1178           if ( myAutomaticPosition )
1179             {
1180               ComputeAutoArcPresentation(theEll, firstp, lastp);
1181             }
1182           else
1183             {
1184               ComputeNotAutoArcPresentation(theEll, firstp, lastp);
1185             }
1186         }
1187       // IV. All others arcs (without common ends)
1188       else
1189         {
1190           // order the parameters; first will be pf1
1191           Standard_Real pl1m = Modulo2PI(pl1 - pf1);
1192           Standard_Real pf2m = Modulo2PI(pf2 - pf1);
1193           Standard_Real pl2m = Modulo2PI(pl2 - pf1);
1194
1195           Standard_Boolean case1 = Standard_False;
1196           // 1 - not intersecting arcs
1197           // 2 - intersecting arcs, but one doesn't contain another
1198           // 3a - first arc contains the second one
1199           // 3b - second arc contains the first one
1200           // 4 - two intersections
1201
1202           gp_Pnt firstp, lastp;
1203
1204           if ( pl1m < pf2m ) // 1 or 2b or 3b
1205             {
1206               if ( pl1m < pl2m ) // 1 or 3b
1207                 {
1208                   if ( pl2m < pf2m ) // 3b
1209                     {
1210                       firstp = firstp1;
1211                       lastp  = lastp1;
1212                     }
1213                   else // 1
1214                     {
1215                       case1 = Standard_True;
1216                       Standard_Real deltap1 = Modulo2PI(pf1 - pl2);
1217                       Standard_Real deltap2 = Modulo2PI(pf2 - pl1);
1218                       if ( ((deltap1 < deltap2) && (deltap1 < 2*rad)) ||
1219                            ((deltap2 < deltap1) && (deltap2 > 2*rad)) ) // deltap2
1220                         {
1221                           firstp = lastp1;
1222                           lastp  = firstp2;
1223                         }
1224                       else // deltap1
1225                         {
1226                           firstp = lastp2;
1227                           lastp  = firstp1;
1228                         }
1229                     }
1230                 }
1231               else // 2b
1232                 {
1233                   firstp = firstp1;
1234                   lastp  = lastp2;
1235                 }
1236             }
1237           else // 2a or 3a or 4
1238             {
1239               if ( pl1m < pl2m ) // 2a
1240                 {
1241                   firstp = firstp2;
1242                   lastp  = lastp1;
1243                 }
1244               else // 3a or 4
1245                 {
1246                   if ( pl2m > pf2m ) // 3a
1247                     {
1248                       firstp = firstp2;
1249                       lastp  = lastp2;
1250                     }
1251                   else // 4
1252                     {
1253                       Standard_Real deltap1 = Modulo2PI(pl1 - pf2);
1254                       Standard_Real deltap2 = Modulo2PI(pl2 - pf1);
1255                       if ( ((deltap1 < deltap2) && (deltap1 < 2*rad)) ||
1256                            ((deltap2 < deltap1) && (deltap2 > 2*rad)) ) // deltap2
1257                         {
1258                           firstp = firstp1;
1259                           lastp  = lastp2;
1260                         }
1261                       else // deltap1
1262                         {
1263                           firstp = firstp2;
1264                           lastp  = lastp1;
1265                         }
1266                     }
1267                 }
1268             }
1269
1270           if ( myAutomaticPosition )
1271             {
1272               ComputeAutoArcPresentation(theEll,firstp,lastp,case1);
1273             }
1274           else
1275             {
1276               if ( case1 )
1277                 {
1278                   myFAttach = firstp;
1279                   mySAttach = lastp;
1280                 }
1281               else ComputeNotAutoArcPresentation(theEll, firstp, lastp);
1282             }
1283         }
1284     }
1285
1286   // Display of the presentation
1287   TCollection_ExtendedString vals(" ==");
1288   gp_Pnt attach = myPosition;
1289   ComputeAttach(theEll->Elips(),myFAttach,mySAttach,attach);
1290   DsgPrs_IdenticPresentation::Add(aPrs,
1291                                   myDrawer,
1292                                   vals,
1293                                   theEll->Elips(),
1294                                   myFAttach,
1295                                   mySAttach,
1296                                   myPosition,
1297                                   attach);
1298 }
1299
1300 //=======================================================================
1301 //function : ComputeAutoArcPresentation
1302 //purpose  : Compute the presentation of the constraint where we are
1303 //           not in the case of dragging.
1304 //=======================================================================
1305 void AIS_IdenticRelation::ComputeAutoArcPresentation(const Handle(Geom_Ellipse)& theEll,
1306                                                      const gp_Pnt& firstp,
1307                                                      const gp_Pnt& lastp,
1308                                                      const Standard_Boolean isstatic)
1309 {
1310   Standard_Real aSegSize = theEll->MajorRadius()/5.0;
1311   Standard_Real rad = M_PI / 5.0;
1312
1313   gp_Elips anEll = theEll->Elips();
1314   
1315   Standard_Real pFA = ElCLib::Parameter(anEll,firstp);
1316   Standard_Real pSA = ElCLib::Parameter(anEll,lastp);
1317   Standard_Real maxrad = Modulo2PI(pSA - pFA)/2.0;
1318   
1319   if ( (rad > maxrad) || isstatic ) rad = maxrad;
1320   Standard_Real pmiddle = Modulo2PI(pFA + Modulo2PI(pSA - pFA)/2.0);
1321   
1322   myFAttach = ElCLib::Value(Modulo2PI(pmiddle - rad),anEll);
1323   mySAttach = ElCLib::Value(Modulo2PI(pmiddle + rad),anEll);
1324   
1325   gp_Pnt curpos = ElCLib::Value(pmiddle,anEll);
1326   gp_Vec vtrans(myCenter, curpos);
1327   vtrans.Normalize();
1328   vtrans *= aSegSize;
1329   myPosition = curpos.Translated(vtrans);
1330 }
1331
1332 //=======================================================================
1333 //function : ComputeNotAutoElipsPresentation
1334 //purpose  : Compute the presentation of the constraint where we are
1335 //           in the case of dragging.
1336 // Note    : This function is to be used only in the case of ellipses.
1337 //           The symbol of the constraint moves only between myFAttach
1338 //           and mySAttach.
1339 //=======================================================================
1340 void AIS_IdenticRelation::ComputeNotAutoElipsPresentation(const Handle(Geom_Ellipse)& theEll)
1341 {
1342   gp_Pnt curpos = myPosition;
1343
1344   gp_Elips anEll = theEll->Elips();
1345   
1346   // Case of confusion between the current position and the center 
1347   // of the ellipse -> we move the current position
1348   Standard_Real confusion (Precision::Confusion());
1349   if ( myCenter.Distance(curpos) <= confusion )
1350     {
1351       gp_Vec vprec(myCenter, myFAttach);
1352       vprec.Normalize();
1353       curpos.Translate(vprec*1e-5);
1354     }
1355   
1356   Standard_Real rad = M_PI / 5.0;
1357 //  Standard_Real pcurpos = ElCLib::Parameter(anEll,curpos);
1358   GeomAPI_ProjectPointOnCurve aProj (curpos, theEll);
1359   Standard_Real pcurpos  = aProj.LowerDistanceParameter();
1360
1361   Standard_Real pFAttach = pcurpos - rad;
1362   Standard_Real pSAttach = pcurpos + rad;
1363   myFAttach = ElCLib::Value(pFAttach,anEll);
1364   mySAttach = ElCLib::Value(pSAttach,anEll);
1365 }
1366
1367 //=======================================================================
1368 //function : ComputeNotAutoArcPresentation
1369 //purpose  : Compute the presentation of the constraint where we are
1370 //           in the case of dragging.
1371 // Note    : This function is to be used only in the case of ellipses.
1372 //           The symbol of the constraint moves only between myFAttach
1373 //           and mySAttach.
1374 //=======================================================================
1375 void AIS_IdenticRelation::ComputeNotAutoArcPresentation(const Handle(Geom_Ellipse)& theEll,
1376                                                         const gp_Pnt& pntfirst,
1377                                                         const gp_Pnt& pntlast)
1378 {
1379   gp_Pnt curpos = myPosition;
1380
1381   gp_Elips anEll = theEll->Elips();
1382
1383   Standard_Real pFPnt = ElCLib::Parameter(anEll, pntfirst);
1384   Standard_Real pSPnt = ElCLib::Parameter(anEll, pntlast);
1385   Standard_Real deltap = Modulo2PI(pSPnt - pFPnt)/2.0;
1386
1387   Standard_Real rad = M_PI / 5;
1388   if ( deltap < rad )
1389     {
1390       myFAttach = pntfirst;
1391       mySAttach = pntlast;
1392     }
1393   else
1394     {
1395       gp_Pnt aFPnt = ElCLib::Value(Modulo2PI(pFPnt + rad), anEll);
1396       gp_Pnt aSPnt = ElCLib::Value(Modulo2PI(pSPnt - rad), anEll);
1397
1398       ComputeAttach(anEll,aFPnt,aSPnt,curpos);
1399
1400 //      Standard_Real pcurpos = ElCLib::Parameter(anEll,curpos);
1401       GeomAPI_ProjectPointOnCurve aProj (curpos, theEll);
1402       Standard_Real pcurpos  = aProj.LowerDistanceParameter();
1403
1404       myFAttach = ElCLib::Value(pcurpos - rad, anEll);
1405       mySAttach = ElCLib::Value(pcurpos + rad, anEll);
1406     }
1407 }
1408 // jfa 18/10/2000 end
1409
1410 //=======================================================================
1411 //function : ComputeTwoVerticesPresentation
1412 //purpose  : 
1413 //=======================================================================
1414 void AIS_IdenticRelation::ComputeTwoVerticesPresentation(const Handle(Prs3d_Presentation)& aPrs)
1415 {
1416   Standard_Boolean isOnPlane1, isOnPlane2;
1417   const TopoDS_Vertex& FVertex = TopoDS::Vertex(myFShape);
1418   const TopoDS_Vertex& SVertex = TopoDS::Vertex(mySShape);
1419   
1420   AIS::ComputeGeometry(FVertex, myFAttach, myPlane, isOnPlane1);
1421   AIS::ComputeGeometry(SVertex, mySAttach, myPlane, isOnPlane2);
1422   
1423   if (isOnPlane1 && isOnPlane2)
1424     myExtShape = 0;
1425   else if ( isOnPlane1 && !isOnPlane2)
1426     myExtShape = 2;
1427   else if (!isOnPlane1 && isOnPlane2)
1428     myExtShape = 1;
1429   else
1430     return ;
1431
1432   
1433   // The attachement points are the points themselves that must be 
1434   //identical
1435   myFAttach = BRep_Tool::Pnt(FVertex);
1436   mySAttach = myFAttach;
1437
1438   gp_Pnt curpos;
1439   if (myAutomaticPosition)
1440     {
1441       //Computation of the size of the symbol
1442       Standard_Real symbsize = ComputeSegSize();
1443       if (symbsize <= Precision::Confusion()) symbsize = 1.;
1444       symbsize*=5;
1445       // Computation of the direction of the segment of the presentation 
1446       // we take the median of the edges connected to vertices
1447       gp_Dir dF, dS;
1448       gp_Dir myDir;
1449       TColStd_ListIteratorOfListOfTransient it(Users());
1450       if (it.More())
1451         {
1452           Handle(AIS_Shape) USER (Handle(AIS_Shape)::DownCast(it.Value()));
1453           if (!USER.IsNull())
1454             {
1455               const TopoDS_Shape& SH =USER->Shape();
1456               if ( (!SH.IsNull()) && (SH.ShapeType() == TopAbs_WIRE) )
1457                 {
1458                   const TopoDS_Wire& WIRE = TopoDS::Wire(USER->Shape());
1459                   Standard_Boolean done = ComputeDirection(WIRE,FVertex,dF);
1460                   if (!done) return;
1461                   done =  ComputeDirection(WIRE,SVertex,dS);
1462                   if (!done) return;
1463                 }
1464               else return;
1465             }
1466           else return;
1467
1468           // computation of the segment direction like average 
1469           // of the 2 computed directions.
1470           if ( dF.IsParallel(dS, Precision::Angular()) )
1471             {
1472               myDir = dF.Crossed(myPlane->Pln().Axis().Direction());
1473             }
1474           else
1475             {
1476               myDir.SetXYZ(dF.XYZ() + dS.XYZ());
1477             }
1478           curpos = myFAttach.Translated(gp_Vec(myDir)*symbsize) ;
1479         }
1480 // jfa 11/10/2000
1481       else
1482         {
1483           curpos = myFAttach;
1484         }
1485 // jfa 11/10/2000 end
1486
1487       myPosition = curpos;
1488       myAutomaticPosition = Standard_False;
1489     }
1490   else
1491     {
1492       curpos = myPosition;
1493     }
1494
1495   // Presentation computation
1496   TCollection_ExtendedString vals(" ++");
1497   DsgPrs_IdenticPresentation::Add(aPrs,
1498                                   myDrawer,
1499                                   vals,
1500                                   myFAttach,
1501                                   curpos);
1502   // Calculate the projection of vertex
1503   if ( myExtShape == 1)
1504     ComputeProjVertexPresentation(aPrs,FVertex,myFAttach);
1505   else if ( myExtShape == 2)
1506     ComputeProjVertexPresentation(aPrs,SVertex,mySAttach);
1507 }
1508
1509
1510
1511 //=======================================================================
1512 //function : ComputeSegSize
1513 //purpose  : 
1514 //=======================================================================
1515 Standard_Real AIS_IdenticRelation::ComputeSegSize() const 
1516 {
1517   return 1.;
1518 }
1519
1520 //=======================================================================
1521 //function : ComputeDirection
1522 //purpose  : Compute a direction according to the different geometric
1523 //           elements connected to the vertex <VERT>, in way to not have
1524 //           overlap between the symbol and them.
1525 //=======================================================================
1526 Standard_Boolean AIS_IdenticRelation::ComputeDirection(const TopoDS_Wire& aWire, 
1527                                                        const TopoDS_Vertex& VERT, 
1528                                                        gp_Dir& dF) const 
1529 {
1530    // we take the median of the edges connected to vertices
1531   TopoDS_Edge edg1,edg2;
1532   ConnectedEdges(aWire,VERT,edg1,edg2);
1533
1534   if ( edg1.IsNull() && edg2.IsNull() ) {
1535     return Standard_False;
1536   }
1537   
1538   Handle(Geom_Curve) curv1,curv2;
1539   gp_Pnt firstp1,lastp1,firstp2,lastp2;
1540
1541   // Case with 2 edges connected to the vertex <VERT>
1542   if ( !edg1.IsNull() && !edg2.IsNull() ) {
1543     if ( !AIS::ComputeGeometry(edg1,edg2,
1544                                curv1,curv2,
1545                                firstp1, lastp1,
1546                                firstp2, lastp2,myPlane))
1547       return Standard_False;
1548
1549     gp_Dir d1, d2;
1550     if ( curv1->IsInstance(STANDARD_TYPE(Geom_Circle)) ) {
1551       d1 = ComputeCircleDirection(Handle(Geom_Circle)::DownCast (curv1), VERT);
1552     }
1553     else if (curv1->IsInstance(STANDARD_TYPE(Geom_Line)) ) {
1554       d1 = ComputeLineDirection(Handle(Geom_Line)::DownCast (curv1), firstp1);
1555     }
1556     else 
1557       return Standard_False;
1558     
1559     if ( curv2->IsInstance(STANDARD_TYPE(Geom_Circle)) ) {
1560       d2 = ComputeCircleDirection( Handle(Geom_Circle)::DownCast (curv2), VERT);
1561     }
1562     else if (curv2->IsInstance(STANDARD_TYPE(Geom_Line)) ) {
1563       d2 =ComputeLineDirection( Handle(Geom_Line)::DownCast (curv2), firstp2);
1564     }
1565     else 
1566       return Standard_False;
1567     
1568     if ( !d1.IsParallel(d2, Precision::Angular() ))
1569       dF.SetXYZ( (d1.XYZ() + d2.XYZ())/2 );
1570     else {
1571       dF= d1.Crossed(myPlane->Pln().Axis().Direction());
1572     }
1573   }
1574
1575   // Case where <VERT> is at an extremity of a wire.
1576   else {
1577     TopoDS_Edge VEdge;
1578     if ( !edg1.IsNull() )  
1579       VEdge = edg1;
1580     else if (!edg2.IsNull() )
1581        VEdge = edg2;
1582     else 
1583       return Standard_False;
1584
1585     if ( !AIS::ComputeGeometry(VEdge, curv1, firstp1, lastp1) )
1586       return Standard_False; 
1587     if ( curv1->IsInstance(STANDARD_TYPE(Geom_Circle)) ) {
1588       dF = ComputeCircleDirection( Handle(Geom_Circle)::DownCast (curv1), VERT);
1589     }
1590     else if (curv1->IsInstance(STANDARD_TYPE(Geom_Line)) ) {
1591       dF = ComputeLineDirection( Handle(Geom_Line)::DownCast (curv1), firstp1);
1592     }
1593     else
1594       return Standard_False;
1595   }
1596
1597   return Standard_True;
1598 }
1599
1600 //=======================================================================
1601 //function : ComputeLineDirection
1602 //purpose  : 
1603 //=======================================================================
1604 gp_Dir AIS_IdenticRelation::ComputeLineDirection(const Handle(Geom_Line)& lin, 
1605                                                  const gp_Pnt& firstP) const 
1606 {
1607   gp_Dir dir;
1608   dir = lin->Lin().Direction();
1609   if ( !myFAttach.IsEqual(firstP, Precision::Confusion()) )
1610     dir.Reverse();
1611   return dir;
1612 }
1613
1614 //=======================================================================
1615 //function : ComputeCircleDirection
1616 //purpose  : 
1617 //=======================================================================
1618 gp_Dir AIS_IdenticRelation::ComputeCircleDirection(const Handle(Geom_Circle)& circ, 
1619                                                    const TopoDS_Vertex& VERT) const 
1620 {
1621   gp_Vec V(circ->Location(),BRep_Tool::Pnt(VERT));
1622   return gp_Dir(V);
1623 }
1624
1625 //=======================================================================
1626 //function : ComputeOneEdgeOVertexPresentation
1627 //purpose  : 
1628 //=======================================================================
1629 void AIS_IdenticRelation::ComputeOneEdgeOVertexPresentation(const Handle(Prs3d_Presentation)& aPrs)
1630 {
1631   TopoDS_Vertex V;
1632   TopoDS_Edge E;
1633   Standard_Integer numedge;
1634   
1635   if (myFShape.ShapeType() == TopAbs_VERTEX) {
1636     V = TopoDS::Vertex(myFShape);
1637     E = TopoDS::Edge(mySShape);
1638     numedge = 2;// edge = 2nd shape
1639   }
1640   else {
1641     V = TopoDS::Vertex(mySShape);
1642     E   = TopoDS::Edge(myFShape);
1643     numedge = 1;  // edge = 1st shape
1644   }
1645   gp_Pnt ptonedge1,ptonedge2;
1646   Handle(Geom_Curve) aCurve;
1647   Handle(Geom_Curve) extCurv;
1648   Standard_Boolean isInfinite;
1649   Standard_Boolean isOnPlanEdge, isOnPlanVertex;
1650   if (!AIS::ComputeGeometry(E,aCurve,ptonedge1,ptonedge2,extCurv,isInfinite,isOnPlanEdge,myPlane))
1651     return;
1652   aPrs->SetInfiniteState(isInfinite);
1653   AIS::ComputeGeometry(V, myFAttach, myPlane, isOnPlanVertex);
1654
1655   // only the curve can be projected 
1656   if (!isOnPlanEdge && !isOnPlanVertex) return;
1657
1658   if (!isOnPlanEdge) {
1659     if (numedge == 1) myExtShape = 1;
1660     else myExtShape = 2;
1661   }
1662   else if (!isOnPlanVertex) {
1663     if (numedge == 1) myExtShape = 2;
1664     else myExtShape = 1;
1665   }
1666   // The attachement points are the point 
1667   myFAttach = BRep_Tool::Pnt(V);
1668   mySAttach = myFAttach;
1669
1670   gp_Pnt curpos;
1671   if (myAutomaticPosition) {
1672     //Computation of the size of the symbol
1673     Standard_Real symbsize = ComputeSegSize();
1674     symbsize*=5;
1675     // Computation of the direction of the segment of the presentation 
1676     // we take the median of the edges connected to vertices
1677     gp_Dir myDir;
1678     if ( aCurve->IsKind(STANDARD_TYPE(Geom_Line))) {
1679       myDir = Handle(Geom_Line)::DownCast (aCurve)->Lin().Direction();
1680       myDir.Cross(myPlane->Pln().Axis().Direction());
1681     }
1682     else if (aCurve->IsKind(STANDARD_TYPE(Geom_Circle))) {
1683       Handle(Geom_Circle) CIR = Handle(Geom_Circle)::DownCast (aCurve);
1684       myDir.SetXYZ(myFAttach.XYZ() - CIR->Location().XYZ());
1685     }
1686     // jfa 10/10/2000
1687     else if (aCurve->IsKind(STANDARD_TYPE(Geom_Ellipse))) {
1688       Handle(Geom_Ellipse) CIR = Handle(Geom_Ellipse)::DownCast (aCurve);
1689       myDir.SetXYZ(myFAttach.XYZ() - CIR->Location().XYZ());
1690     }
1691     // jfa 10/10/2000 end
1692
1693     curpos = myFAttach.Translated(gp_Vec(myDir)*symbsize) ;
1694     myPosition = curpos;
1695     myAutomaticPosition = Standard_True;
1696   }
1697   else {
1698     curpos = myPosition;
1699   }
1700
1701   // Presentation computation
1702   TCollection_ExtendedString vals(" -+-");
1703   DsgPrs_IdenticPresentation::Add(aPrs,
1704                                   myDrawer,
1705                                   vals,
1706                                   myFAttach,
1707                                   curpos);
1708   if (myExtShape != 0) {
1709     if (!extCurv.IsNull()) { // the edge is not in the WP
1710      ComputeProjEdgePresentation(aPrs,E,Handle(Geom_Line)::DownCast (aCurve),ptonedge1,ptonedge2);
1711     }
1712   }
1713 }