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