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