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