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