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