0031431: Visualization, PrsMgr_PresentableObject - simplify HLR computing interface
[occt.git] / src / AIS / AIS_FixRelation.cxx
1 // Created on: 1996-12-05
2 // Created by: Flore Lantheaume/Odile Olivier
3 // Copyright (c) 1996-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17
18 #include <AIS.hxx>
19 #include <AIS_FixRelation.hxx>
20 #include <AIS_Shape.hxx>
21 #include <BRep_Tool.hxx>
22 #include <BRepAdaptor_Curve.hxx>
23 #include <DsgPrs_FixPresentation.hxx>
24 #include <ElCLib.hxx>
25 #include <ElSLib.hxx>
26 #include <Geom_Circle.hxx>
27 #include <Geom_Curve.hxx>
28 #include <Geom_Line.hxx>
29 #include <Geom_Plane.hxx>
30 #include <Geom_Transformation.hxx>
31 #include <gp_Ax1.hxx>
32 #include <gp_Circ.hxx>
33 #include <gp_Dir.hxx>
34 #include <gp_Lin.hxx>
35 #include <gp_Pnt.hxx>
36 #include <gp_Vec.hxx>
37 #include <gp_XYZ.hxx>
38 #include <Precision.hxx>
39 #include <Prs3d_Presentation.hxx>
40 #include <Select3D_SensitiveSegment.hxx>
41 #include <SelectMgr_EntityOwner.hxx>
42 #include <SelectMgr_Selection.hxx>
43 #include <Standard_DomainError.hxx>
44 #include <Standard_NotImplemented.hxx>
45 #include <Standard_Type.hxx>
46 #include <TColStd_ListIteratorOfListOfTransient.hxx>
47 #include <TopAbs_ShapeEnum.hxx>
48 #include <TopExp.hxx>
49 #include <TopLoc_Location.hxx>
50 #include <TopoDS.hxx>
51 #include <TopoDS_Edge.hxx>
52 #include <TopoDS_Shape.hxx>
53 #include <TopoDS_Vertex.hxx>
54 #include <TopoDS_Wire.hxx>
55 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
56 #include <TopTools_IndexedMapOfShape.hxx>
57 #include <TopTools_ListIteratorOfListOfShape.hxx>
58
59 IMPLEMENT_STANDARD_RTTIEXT(AIS_FixRelation,AIS_Relation)
60
61 static Standard_Boolean InDomain(const Standard_Real fpar,
62                                         const Standard_Real lpar,
63                                         const Standard_Real para) 
64 {
65   if (fpar >= 0.) {
66     return ((para >= fpar) && (para <= lpar));
67   }
68   if (para >= (fpar+2*M_PI)) return Standard_True;
69   if (para <= lpar) return Standard_True;
70   return Standard_False;
71 }
72
73 //=======================================================================
74 //function : Constructor
75 //purpose  : vertex Fix Relation
76 //=======================================================================
77
78 AIS_FixRelation::AIS_FixRelation(const TopoDS_Shape& aShape, 
79                                  const Handle(Geom_Plane)& aPlane, 
80                                  const TopoDS_Wire& aWire)
81 :AIS_Relation(),
82  myWire(aWire)
83 {
84   myFShape = aShape;
85   myPlane = aPlane;
86   myAutomaticPosition = Standard_True;
87   myArrowSize = 5.;
88 }
89
90 //=======================================================================
91 //function : Constructor
92 //purpose  : vertex Fix Relation
93 //=======================================================================
94
95 AIS_FixRelation::AIS_FixRelation(const TopoDS_Shape& aShape, 
96                                  const Handle(Geom_Plane)& aPlane, 
97                                  const TopoDS_Wire& aWire, 
98                                  const gp_Pnt& aPosition, 
99                                  const Standard_Real anArrowSize)
100 :AIS_Relation(),
101  myWire(aWire)
102 {
103   myFShape = aShape;
104   myPlane = aPlane;
105   myPosition = aPosition;
106   SetArrowSize( anArrowSize );
107   myAutomaticPosition = Standard_False;
108 }
109
110
111 //=======================================================================
112 //function : Constructor
113 //purpose  : edge (line or circle) Fix Relation
114 //=======================================================================
115
116 AIS_FixRelation::AIS_FixRelation(const TopoDS_Shape& aShape, 
117                                  const Handle(Geom_Plane)& aPlane)
118 {
119   myFShape = aShape;
120   myPlane = aPlane;
121   myAutomaticPosition = Standard_True;
122   myArrowSize = 5.;
123 }
124
125 //=======================================================================
126 //function : Constructor
127 //purpose  : edge (line or circle) Fix Relation
128 //=======================================================================
129
130 AIS_FixRelation::AIS_FixRelation(
131         const TopoDS_Shape& aShape, 
132         const Handle(Geom_Plane)& aPlane, 
133         const gp_Pnt& aPosition, 
134         const Standard_Real anArrowSize)
135 {
136   myFShape = aShape;
137   myPlane = aPlane;
138   myPosition = aPosition;
139   SetArrowSize( anArrowSize );
140   myAutomaticPosition = Standard_False;
141 }
142
143 //=======================================================================
144 //function : Wire
145 //purpose  : 
146 //=======================================================================
147
148 TopoDS_Wire AIS_FixRelation::Wire()
149 {
150   return myWire;
151 }
152
153 //=======================================================================
154 //function : SetWire
155 //purpose  : 
156 //=======================================================================
157
158 void AIS_FixRelation::SetWire(const TopoDS_Wire& aWire)
159 {
160   myWire = aWire;
161 }
162
163
164 //=======================================================================
165 //function : Compute
166 //purpose  : 
167 //=======================================================================
168
169 void AIS_FixRelation::Compute(const Handle(PrsMgr_PresentationManager3d)&, 
170                               const Handle(Prs3d_Presentation)& aPresentation, 
171                               const Standard_Integer)
172 {
173   // Calculate position of the symbol and
174   // point of attach of the segment on the shape
175   gp_Pnt curpos;
176   if (myFShape.ShapeType() == TopAbs_VERTEX)
177     ComputeVertex(TopoDS::Vertex(myFShape), curpos);
178   else if (myFShape.ShapeType() == TopAbs_EDGE)
179     ComputeEdge(TopoDS::Edge(myFShape), curpos);
180
181   const gp_Dir& nor = myPlane->Axis().Direction();
182
183   
184   // calculate presentation
185   // definition of the symbol size
186   if( !myArrowSizeIsDefined )
187     myArrowSize = 5.;
188
189     //creation of the presentation
190   DsgPrs_FixPresentation::Add(aPresentation,
191                               myDrawer,
192                               myPntAttach,
193                               curpos,
194                               nor,
195                               myArrowSize);
196 }
197
198 //=======================================================================
199 //function : ComputeSelection
200 //purpose  : 
201 //=======================================================================
202
203 void AIS_FixRelation::ComputeSelection(const Handle(SelectMgr_Selection)& aSelection, 
204                                        const Standard_Integer)
205 {
206   Handle(SelectMgr_EntityOwner) own = new SelectMgr_EntityOwner(this,7);
207
208   // creation of segment sensible for the linked segment  
209   // of the shape fixed to symbol 'Fix'
210   Handle(Select3D_SensitiveSegment) seg;
211   seg = new Select3D_SensitiveSegment(own,
212                                       myPntAttach,
213                                       myPosition);
214   aSelection->Add(seg);
215   
216   // Creation of the sensible zone of symbol 'Fix'
217   gp_Dir norm = myPlane->Axis().Direction();
218     
219   gp_Vec dirac(myPntAttach,myPosition);
220   dirac.Normalize();
221   gp_Vec norac = dirac.Crossed(gp_Vec(norm));
222   gp_Ax1 ax(myPosition, norm);
223   norac.Rotate(ax, M_PI/8);
224
225   norac*=(myArrowSize/2);
226   gp_Pnt P1 = myPosition.Translated(norac);
227   gp_Pnt P2 = myPosition.Translated(-norac);
228   seg = new Select3D_SensitiveSegment(own,
229                                       P1,
230                                       P2);
231   aSelection->Add(seg);
232
233   norac*=0.8;
234   P1 = myPosition.Translated(norac);
235   P2 = myPosition.Translated(-norac);
236   dirac*=(myArrowSize/2);
237   gp_Pnt PF(P1.XYZ());
238   gp_Pnt PL = PF.Translated(dirac);
239   PL.Translate(norac);
240   seg = new Select3D_SensitiveSegment(own,
241                                       PF,
242                                       PL);
243   aSelection->Add(seg);
244
245
246   PF.SetXYZ(P2.XYZ());
247   PL = PF.Translated(dirac);
248   PL.Translate(norac);
249   seg = new Select3D_SensitiveSegment(own,
250                                       PF,
251                                       PL);
252   aSelection->Add(seg);
253
254   PF.SetXYZ( (P1.XYZ() + P2.XYZ()) /2 );
255   PL = PF.Translated(dirac);
256   PL.Translate(norac);
257   seg = new Select3D_SensitiveSegment(own,
258                                       PF,
259                                       PL);
260 }
261
262 //=======================================================================
263 //function : ComputeVertex
264 //purpose  : computes myPntAttach and the position of the presentation 
265 //           when you fix a vertex
266 //=======================================================================
267
268 void AIS_FixRelation::ComputeVertex(const TopoDS_Vertex& /*FixVertex*/,
269                                     gp_Pnt& curpos)
270 {
271   myPntAttach = BRep_Tool::Pnt(TopoDS::Vertex(myFShape));
272   curpos = myPosition;
273   if (myAutomaticPosition) {
274       gp_Pln pln(myPlane->Pln());
275       gp_Dir dir(pln.XAxis().Direction());
276       gp_Vec transvec = gp_Vec(dir)*myArrowSize;
277       curpos = myPntAttach.Translated(transvec);
278       myPosition = curpos;
279       myAutomaticPosition = Standard_True;
280   }
281 }
282
283 //=======================================================================
284 //function : ComputePosition
285 //purpose  : 
286 //=======================================================================
287
288 gp_Pnt AIS_FixRelation::ComputePosition(const Handle(Geom_Curve)& curv1, 
289                                         const Handle(Geom_Curve)& curv2, 
290                                         const gp_Pnt& firstp1, 
291                                         const gp_Pnt& lastp1, 
292                                         const gp_Pnt& firstp2, 
293                                         const gp_Pnt& lastp2) const 
294 {
295   //---------------------------------------------------------
296   // calculate the point of attach
297   //---------------------------------------------------------
298   gp_Pnt curpos;
299
300   if (curv1->IsInstance(STANDARD_TYPE(Geom_Circle)) || curv2->IsInstance(STANDARD_TYPE(Geom_Circle))) {    
301     Handle(Geom_Circle) gcirc = Handle(Geom_Circle)::DownCast(curv1);
302     if (gcirc.IsNull()) gcirc = Handle(Geom_Circle)::DownCast(curv2);
303     gp_Dir dir( gcirc->Location().XYZ() + myPntAttach.XYZ() );
304     gp_Vec transvec = gp_Vec(dir)*myArrowSize;
305     curpos = myPntAttach.Translated(transvec);    
306   }
307
308   else {
309     gp_Vec vec1(firstp1,lastp1);
310     gp_Vec vec2(firstp2,lastp2);
311     
312     if (!vec1.IsParallel(vec2, Precision::Angular()) ) {
313       gp_Dir dir;
314       Standard_Real conf =Precision::Confusion();
315       if (lastp1.IsEqual(firstp2,conf) || firstp1.IsEqual(lastp2,conf)) dir.SetXYZ(vec1.XYZ() - vec2.XYZ());
316       else dir.SetXYZ(vec1.XYZ() + vec2.XYZ());
317       gp_Vec transvec = gp_Vec(dir)*myArrowSize;
318       curpos = myPntAttach.Translated(transvec);
319     }
320     else {
321       gp_Vec crossvec = vec1.Crossed(vec2);
322       vec1.Cross(crossvec);
323       gp_Dir dir(vec1);
324       curpos = myPntAttach.Translated(gp_Vec(dir)*myArrowSize);
325     }
326   }
327
328   return curpos;
329 }
330
331 //=======================================================================
332 //function : ComputePosition
333 //purpose  : Computes the position of the "fix dimension" when the 
334 //           fixed object is a vertex which is set at the intersection
335 //           of two curves.
336 //           The "dimension" is in the "middle" of the two edges.
337 //=======================================================================
338
339 gp_Pnt AIS_FixRelation::ComputePosition(const Handle(Geom_Curve)& curv, 
340                                         const gp_Pnt& firstp, 
341                                         const gp_Pnt& lastp) const 
342 {
343   //---------------------------------------------------------
344   // calculate the point of attach
345   //---------------------------------------------------------
346   gp_Pnt curpos;
347
348   if (curv->IsKind(STANDARD_TYPE(Geom_Circle))) {
349     
350     Handle(Geom_Circle) gcirc = Handle(Geom_Circle)::DownCast(curv);
351     gp_Dir dir( gcirc->Location().XYZ() + myPntAttach.XYZ() );
352     gp_Vec transvec = gp_Vec(dir)*myArrowSize;
353     curpos = myPntAttach.Translated(transvec);
354     
355   } //if (curv->IsKind(STANDARD_TYPE(Geom_Circle))
356
357   else {
358 //    gp_Pln pln(Component()->WorkingPlane()->Plane()->GetValue()->Pln());
359     gp_Pln pln(myPlane->Pln());
360     gp_Dir NormPln = pln.Axis().Direction();
361     gp_Vec vec(firstp,lastp);
362     vec.Cross( gp_Vec(NormPln));
363     vec.Normalize();
364     gp_Vec transvec = vec*myArrowSize;
365     curpos = myPntAttach.Translated(transvec);
366     gp_Ax1 RotAx( myPntAttach, NormPln);
367     curpos.Rotate(RotAx, M_PI/10);
368   }
369
370   return curpos;
371  }
372
373 //=======================================================================
374 //function : ComputeEdge 
375 //purpose  : computes myPntAttach and the position of the presentation 
376 //           when you fix an edge
377 //=======================================================================
378
379 void AIS_FixRelation::ComputeEdge(const TopoDS_Edge& FixEdge, gp_Pnt& curpos)
380 {
381   Handle(Geom_Curve) curEdge;
382   gp_Pnt ptbeg,ptend;
383   if (!AIS::ComputeGeometry(FixEdge,curEdge,ptbeg,ptend)) return;
384
385   //---------------------------------------------------------
386   // calcul du point de positionnement du symbole 'fix'
387   //---------------------------------------------------------
388         //--> In case of a straight line
389   if (curEdge->IsKind(STANDARD_TYPE(Geom_Line))){
390     gp_Lin glin = Handle(Geom_Line)::DownCast(curEdge)->Lin();
391     Standard_Real pfirst(ElCLib::Parameter(glin,ptbeg));
392     Standard_Real plast(ElCLib::Parameter(glin,ptend));
393     ComputeLinePosition(glin, curpos, pfirst, plast);
394   }
395   
396         //--> In case of a circle
397   else if (curEdge->IsKind(STANDARD_TYPE(Geom_Circle))) {
398     gp_Circ  gcirc = Handle(Geom_Circle)::DownCast(curEdge)->Circ();
399     Standard_Real pfirst, plast;
400     BRepAdaptor_Curve cu(FixEdge);
401     pfirst = cu.FirstParameter();
402     plast = cu.LastParameter();
403     ComputeCirclePosition(gcirc, curpos, pfirst, plast);
404   }
405   
406   else
407     return;
408     
409 }
410
411 //=======================================================================
412 //function : ComputeLinePosition
413 //purpose  : compute the values of myPntAttach and the position <pos> of
414 //           the symbol when the fixed edge has a geometric support equal
415 //           to a line.
416 //=======================================================================
417
418 void AIS_FixRelation::ComputeLinePosition(const gp_Lin& glin, 
419                                           gp_Pnt& pos, 
420                                           Standard_Real& pfirst, 
421                                           Standard_Real& plast)
422 {
423   if (myAutomaticPosition) {
424     // point of attach is chosen as middle of the segment
425     myPntAttach = ElCLib::Value((pfirst+ plast)/2, glin);
426     
427     gp_Dir norm = myPlane ->Axis().Direction();
428      
429     norm.Cross(glin.Position().Direction());
430     pos = myPntAttach.Translated(gp_Vec(norm)*myArrowSize);
431     myAutomaticPosition = Standard_True;
432   } // if (myAutomaticPosition)
433
434   else {
435     pos = myPosition;
436     Standard_Real linparam = ElCLib::Parameter(glin, pos);
437
438     // case if the projection of position is located between 2 vertices
439     // de l'edge
440     if ( (linparam >= pfirst) && (linparam <= plast) )
441       myPntAttach = ElCLib::Value(linparam,glin);
442     
443     // case if the projection of Position is outside of the limits
444     // of the edge : the point closest to the projection is chosen 
445     // as the attach point
446     else {
447       Standard_Real pOnLin;
448       if (linparam > plast)
449         pOnLin = plast;
450       else
451         pOnLin = pfirst;
452       myPntAttach = ElCLib::Value(pOnLin,glin);
453       gp_Dir norm = myPlane->Axis().Direction();
454         
455       norm.Cross(glin.Position().Direction());
456       gp_Lin lsup(myPntAttach, norm);
457       Standard_Real parpos = ElCLib::Parameter(lsup,myPosition);
458       pos =  ElCLib::Value(parpos,lsup);
459     }
460
461   }
462   myPosition = pos;
463 }
464
465 //=======================================================================
466 //function : ComputeCirclePosition 
467 //purpose  : compute the values of myPntAttach and the position <pos> of
468 //           the symbol when the fixed edge has a geometric support equal
469 //           to a circle. 
470 //=======================================================================
471
472 void AIS_FixRelation::ComputeCirclePosition(
473         const gp_Circ& gcirc, 
474         gp_Pnt& pos, 
475         Standard_Real& pfirst, 
476         Standard_Real& plast)
477 {
478   // readjust parametres on the circle
479   if (plast > 2*M_PI ) {
480     Standard_Real nbtours = Floor(plast / (2*M_PI));
481     plast -= nbtours*2*M_PI;
482     pfirst -= nbtours*2*M_PI;
483   }
484
485   if (myAutomaticPosition) {
486     // the point attach is the "middle" of the segment (relatively
487     // to the parametres of start and end vertices of the edge
488     
489     Standard_Real circparam = (pfirst + plast)/2.;
490
491     if ( !InDomain(pfirst,plast,circparam)) {
492       Standard_Real otherpar = circparam + M_PI;
493       if (otherpar > 2*M_PI) otherpar -= 2*M_PI;
494       circparam = otherpar;
495     }
496
497     myPntAttach = ElCLib::Value(circparam, gcirc );
498
499     gp_Vec dir( gcirc.Location().XYZ(), myPntAttach.XYZ() );
500     dir.Normalize();
501     gp_Vec transvec = dir*myArrowSize;
502     pos = myPntAttach.Translated(transvec);
503     myPosition = pos;
504     myAutomaticPosition = Standard_True;
505   } // if (myAutomaticPosition)
506
507   else {
508     // case if the projection of myPosition is outside of 2
509     // vertices of the edge. In this case the parameter is readjusted
510     // in the valid part of the circle
511     pos = myPosition;
512
513     Standard_Real circparam = ElCLib::Parameter(gcirc, pos);
514
515     if ( !InDomain(pfirst,plast,circparam)) {
516       Standard_Real otherpar = circparam + M_PI;
517       if (otherpar > 2*M_PI) otherpar -= 2*M_PI;
518       circparam = otherpar;
519     }
520     
521     myPntAttach = ElCLib::Value(circparam,gcirc);
522   }
523 }
524
525 //=======================================================================
526 //function : ConnectedEdges
527 //purpose  : 
528 //=======================================================================
529 Standard_Boolean AIS_FixRelation::ConnectedEdges(const TopoDS_Wire& WIRE,
530                                                  const TopoDS_Vertex& V, 
531                                                  TopoDS_Edge& E1, 
532                                                  TopoDS_Edge& E2)
533 {
534   TopTools_IndexedDataMapOfShapeListOfShape  vertexMap;
535   TopExp::MapShapesAndAncestors (WIRE,TopAbs_VERTEX,TopAbs_EDGE,vertexMap);
536   
537   Standard_Boolean found(Standard_False);
538   TopoDS_Vertex theVertex;
539   for (Standard_Integer i=1; i<=vertexMap.Extent() && !found; i++) {
540     if (vertexMap.FindKey(i).IsSame(V)) {
541      theVertex = TopoDS::Vertex(vertexMap.FindKey(i));
542      found = Standard_True;
543    }
544   }
545   if (!found) {
546     E1.Nullify();
547     E2.Nullify();
548     return Standard_False;
549   }
550
551   TopTools_ListIteratorOfListOfShape iterator(vertexMap.FindFromKey(theVertex));
552   if (iterator.More()) {
553     E1 = TopoDS::Edge(iterator.Value());
554     BRepAdaptor_Curve curv(E1);
555     iterator.Next();
556   }
557   else {
558     E1.Nullify();
559     return Standard_False;
560   }
561
562   if (iterator.More()) {
563     E2 = TopoDS::Edge(iterator.Value());
564     BRepAdaptor_Curve curv(E2);
565     iterator.Next();
566   }
567   else {
568     E2.Nullify();
569     return Standard_False;
570   }
571     
572   if (iterator.More()) {
573     E1.Nullify();
574     E2.Nullify();
575     return Standard_False;
576   }
577   return Standard_True;
578 }