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