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 
IMPLEMENT_STANDARD_RTTIEXT(PrsDim_FixRelation,PrsDim_Relation)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 
PrsDim_FixRelation(const TopoDS_Shape & aShape,const Handle (Geom_Plane)& aPlane,const TopoDS_Wire & aWire)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 
PrsDim_FixRelation(const TopoDS_Shape & aShape,const Handle (Geom_Plane)& aPlane,const TopoDS_Wire & aWire,const gp_Pnt & aPosition,const Standard_Real anArrowSize)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 
PrsDim_FixRelation(const TopoDS_Shape & aShape,const Handle (Geom_Plane)& aPlane)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 
PrsDim_FixRelation(const TopoDS_Shape & aShape,const Handle (Geom_Plane)& aPlane,const gp_Pnt & aPosition,const Standard_Real anArrowSize)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 //=======================================================================
Compute(const Handle (PrsMgr_PresentationManager)&,const Handle (Prs3d_Presentation)& aPresentation,const Standard_Integer)144 void PrsDim_FixRelation::Compute (const Handle(PrsMgr_PresentationManager)& ,
145                                   const Handle(Prs3d_Presentation)& aPresentation,
146                                   const Standard_Integer )
147 {
148   // Calculate position of the symbol and
149   // point of attach of the segment on the shape
150   gp_Pnt curpos;
151   if (myFShape.ShapeType() == TopAbs_VERTEX)
152     ComputeVertex(TopoDS::Vertex(myFShape), curpos);
153   else if (myFShape.ShapeType() == TopAbs_EDGE)
154     ComputeEdge(TopoDS::Edge(myFShape), curpos);
155 
156   const gp_Dir& nor = myPlane->Axis().Direction();
157 
158 
159   // calculate presentation
160   // definition of the symbol size
161   if( !myArrowSizeIsDefined )
162     myArrowSize = 5.;
163 
164     //creation of the presentation
165   DsgPrs_FixPresentation::Add(aPresentation,
166 			      myDrawer,
167 			      myPntAttach,
168 			      curpos,
169 			      nor,
170 			      myArrowSize);
171 }
172 
173 //=======================================================================
174 //function : ComputeSelection
175 //purpose  :
176 //=======================================================================
177 
ComputeSelection(const Handle (SelectMgr_Selection)& aSelection,const Standard_Integer)178 void PrsDim_FixRelation::ComputeSelection(const Handle(SelectMgr_Selection)& aSelection,
179 				       const Standard_Integer)
180 {
181   Handle(SelectMgr_EntityOwner) own = new SelectMgr_EntityOwner(this,7);
182 
183   // creation of segment sensible for the linked segment
184   // of the shape fixed to symbol 'Fix'
185   Handle(Select3D_SensitiveSegment) seg;
186   seg = new Select3D_SensitiveSegment(own,
187 				      myPntAttach,
188 				      myPosition);
189   aSelection->Add(seg);
190 
191   // Creation of the sensible zone of symbol 'Fix'
192   gp_Dir norm = myPlane->Axis().Direction();
193 
194   gp_Vec dirac(myPntAttach,myPosition);
195   dirac.Normalize();
196   gp_Vec norac = dirac.Crossed(gp_Vec(norm));
197   gp_Ax1 ax(myPosition, norm);
198   norac.Rotate(ax, M_PI/8);
199 
200   norac*=(myArrowSize/2);
201   gp_Pnt P1 = myPosition.Translated(norac);
202   gp_Pnt P2 = myPosition.Translated(-norac);
203   seg = new Select3D_SensitiveSegment(own,
204 				      P1,
205 				      P2);
206   aSelection->Add(seg);
207 
208   norac*=0.8;
209   P1 = myPosition.Translated(norac);
210   P2 = myPosition.Translated(-norac);
211   dirac*=(myArrowSize/2);
212   gp_Pnt PF(P1.XYZ());
213   gp_Pnt PL = PF.Translated(dirac);
214   PL.Translate(norac);
215   seg = new Select3D_SensitiveSegment(own,
216 				      PF,
217 				      PL);
218   aSelection->Add(seg);
219 
220 
221   PF.SetXYZ(P2.XYZ());
222   PL = PF.Translated(dirac);
223   PL.Translate(norac);
224   seg = new Select3D_SensitiveSegment(own,
225 				      PF,
226 				      PL);
227   aSelection->Add(seg);
228 
229   PF.SetXYZ( (P1.XYZ() + P2.XYZ()) /2 );
230   PL = PF.Translated(dirac);
231   PL.Translate(norac);
232   seg = new Select3D_SensitiveSegment(own,
233 				      PF,
234 				      PL);
235 }
236 
237 //=======================================================================
238 //function : ComputeVertex
239 //purpose  : computes myPntAttach and the position of the presentation
240 //           when you fix a vertex
241 //=======================================================================
242 
ComputeVertex(const TopoDS_Vertex &,gp_Pnt & curpos)243 void PrsDim_FixRelation::ComputeVertex(const TopoDS_Vertex& /*FixVertex*/,
244 				    gp_Pnt& curpos)
245 {
246   myPntAttach = BRep_Tool::Pnt(TopoDS::Vertex(myFShape));
247   curpos = myPosition;
248   if (myAutomaticPosition) {
249       gp_Pln pln(myPlane->Pln());
250       gp_Dir dir(pln.XAxis().Direction());
251       gp_Vec transvec = gp_Vec(dir)*myArrowSize;
252       curpos = myPntAttach.Translated(transvec);
253       myPosition = curpos;
254       myAutomaticPosition = Standard_True;
255   }
256 }
257 
258 //=======================================================================
259 //function : ComputePosition
260 //purpose  :
261 //=======================================================================
262 
ComputePosition(const Handle (Geom_Curve)& curv1,const Handle (Geom_Curve)& curv2,const gp_Pnt & firstp1,const gp_Pnt & lastp1,const gp_Pnt & firstp2,const gp_Pnt & lastp2) const263 gp_Pnt PrsDim_FixRelation::ComputePosition(const Handle(Geom_Curve)& curv1,
264 					const Handle(Geom_Curve)& curv2,
265 					const gp_Pnt& firstp1,
266 					const gp_Pnt& lastp1,
267 					const gp_Pnt& firstp2,
268 					const gp_Pnt& lastp2) const
269 {
270   //---------------------------------------------------------
271   // calculate the point of attach
272   //---------------------------------------------------------
273   gp_Pnt curpos;
274 
275   if (curv1->IsInstance(STANDARD_TYPE(Geom_Circle)) || curv2->IsInstance(STANDARD_TYPE(Geom_Circle))) {
276     Handle(Geom_Circle) gcirc = Handle(Geom_Circle)::DownCast(curv1);
277     if (gcirc.IsNull()) gcirc = Handle(Geom_Circle)::DownCast(curv2);
278     gp_Dir dir( gcirc->Location().XYZ() + myPntAttach.XYZ() );
279     gp_Vec transvec = gp_Vec(dir)*myArrowSize;
280     curpos = myPntAttach.Translated(transvec);
281   }
282 
283   else {
284     gp_Vec vec1(firstp1,lastp1);
285     gp_Vec vec2(firstp2,lastp2);
286 
287     if (!vec1.IsParallel(vec2, Precision::Angular()) ) {
288       gp_Dir dir;
289       Standard_Real conf =Precision::Confusion();
290       if (lastp1.IsEqual(firstp2,conf) || firstp1.IsEqual(lastp2,conf)) dir.SetXYZ(vec1.XYZ() - vec2.XYZ());
291       else dir.SetXYZ(vec1.XYZ() + vec2.XYZ());
292       gp_Vec transvec = gp_Vec(dir)*myArrowSize;
293       curpos = myPntAttach.Translated(transvec);
294     }
295     else {
296       gp_Vec crossvec = vec1.Crossed(vec2);
297       vec1.Cross(crossvec);
298       gp_Dir dir(vec1);
299       curpos = myPntAttach.Translated(gp_Vec(dir)*myArrowSize);
300     }
301   }
302 
303   return curpos;
304 }
305 
306 //=======================================================================
307 //function : ComputePosition
308 //purpose  : Computes the position of the "fix dimension" when the
309 //           fixed object is a vertex which is set at the intersection
310 //           of two curves.
311 //           The "dimension" is in the "middle" of the two edges.
312 //=======================================================================
313 
ComputePosition(const Handle (Geom_Curve)& curv,const gp_Pnt & firstp,const gp_Pnt & lastp) const314 gp_Pnt PrsDim_FixRelation::ComputePosition(const Handle(Geom_Curve)& curv,
315 					const gp_Pnt& firstp,
316 					const gp_Pnt& lastp) const
317 {
318   //---------------------------------------------------------
319   // calculate the point of attach
320   //---------------------------------------------------------
321   gp_Pnt curpos;
322 
323   if (curv->IsKind(STANDARD_TYPE(Geom_Circle))) {
324 
325     Handle(Geom_Circle) gcirc = Handle(Geom_Circle)::DownCast(curv);
326     gp_Dir dir( gcirc->Location().XYZ() + myPntAttach.XYZ() );
327     gp_Vec transvec = gp_Vec(dir)*myArrowSize;
328     curpos = myPntAttach.Translated(transvec);
329 
330   } //if (curv->IsKind(STANDARD_TYPE(Geom_Circle))
331 
332   else {
333 //    gp_Pln pln(Component()->WorkingPlane()->Plane()->GetValue()->Pln());
334     gp_Pln pln(myPlane->Pln());
335     gp_Dir NormPln = pln.Axis().Direction();
336     gp_Vec vec(firstp,lastp);
337     vec.Cross( gp_Vec(NormPln));
338     vec.Normalize();
339     gp_Vec transvec = vec*myArrowSize;
340     curpos = myPntAttach.Translated(transvec);
341     gp_Ax1 RotAx( myPntAttach, NormPln);
342     curpos.Rotate(RotAx, M_PI/10);
343   }
344 
345   return curpos;
346  }
347 
348 //=======================================================================
349 //function : ComputeEdge
350 //purpose  : computes myPntAttach and the position of the presentation
351 //           when you fix an edge
352 //=======================================================================
353 
ComputeEdge(const TopoDS_Edge & FixEdge,gp_Pnt & curpos)354 void PrsDim_FixRelation::ComputeEdge(const TopoDS_Edge& FixEdge, gp_Pnt& curpos)
355 {
356   Handle(Geom_Curve) curEdge;
357   gp_Pnt ptbeg,ptend;
358   if (!PrsDim::ComputeGeometry(FixEdge,curEdge,ptbeg,ptend)) return;
359 
360   //---------------------------------------------------------
361   // calcul du point de positionnement du symbole 'fix'
362   //---------------------------------------------------------
363         //--> In case of a straight line
364   if (curEdge->IsKind(STANDARD_TYPE(Geom_Line))){
365     gp_Lin glin = Handle(Geom_Line)::DownCast(curEdge)->Lin();
366     Standard_Real pfirst(ElCLib::Parameter(glin,ptbeg));
367     Standard_Real plast(ElCLib::Parameter(glin,ptend));
368     ComputeLinePosition(glin, curpos, pfirst, plast);
369   }
370 
371         //--> In case of a circle
372   else if (curEdge->IsKind(STANDARD_TYPE(Geom_Circle))) {
373     gp_Circ  gcirc = Handle(Geom_Circle)::DownCast(curEdge)->Circ();
374     Standard_Real pfirst, plast;
375     BRepAdaptor_Curve cu(FixEdge);
376     pfirst = cu.FirstParameter();
377     plast = cu.LastParameter();
378     ComputeCirclePosition(gcirc, curpos, pfirst, plast);
379   }
380 
381   else
382     return;
383 
384 }
385 
386 //=======================================================================
387 //function : ComputeLinePosition
388 //purpose  : compute the values of myPntAttach and the position <pos> of
389 //           the symbol when the fixed edge has a geometric support equal
390 //           to a line.
391 //=======================================================================
392 
ComputeLinePosition(const gp_Lin & glin,gp_Pnt & pos,Standard_Real & pfirst,Standard_Real & plast)393 void PrsDim_FixRelation::ComputeLinePosition(const gp_Lin& glin,
394 					  gp_Pnt& pos,
395 					  Standard_Real& pfirst,
396 					  Standard_Real& plast)
397 {
398   if (myAutomaticPosition) {
399     // point of attach is chosen as middle of the segment
400     myPntAttach = ElCLib::Value((pfirst+ plast)/2, glin);
401 
402     gp_Dir norm = myPlane ->Axis().Direction();
403 
404     norm.Cross(glin.Position().Direction());
405     pos = myPntAttach.Translated(gp_Vec(norm)*myArrowSize);
406     myAutomaticPosition = Standard_True;
407   } // if (myAutomaticPosition)
408 
409   else {
410     pos = myPosition;
411     Standard_Real linparam = ElCLib::Parameter(glin, pos);
412 
413     // case if the projection of position is located between 2 vertices
414     // de l'edge
415     if ( (linparam >= pfirst) && (linparam <= plast) )
416       myPntAttach = ElCLib::Value(linparam,glin);
417 
418     // case if the projection of Position is outside of the limits
419     // of the edge : the point closest to the projection is chosen
420     // as the attach point
421     else {
422       Standard_Real pOnLin;
423       if (linparam > plast)
424 	pOnLin = plast;
425       else
426 	pOnLin = pfirst;
427       myPntAttach = ElCLib::Value(pOnLin,glin);
428       gp_Dir norm = myPlane->Axis().Direction();
429 
430       norm.Cross(glin.Position().Direction());
431       gp_Lin lsup(myPntAttach, norm);
432       Standard_Real parpos = ElCLib::Parameter(lsup,myPosition);
433       pos =  ElCLib::Value(parpos,lsup);
434     }
435 
436   }
437   myPosition = pos;
438 }
439 
440 //=======================================================================
441 //function : ComputeCirclePosition
442 //purpose  : compute the values of myPntAttach and the position <pos> of
443 //           the symbol when the fixed edge has a geometric support equal
444 //           to a circle.
445 //=======================================================================
446 
ComputeCirclePosition(const gp_Circ & gcirc,gp_Pnt & pos,Standard_Real & pfirst,Standard_Real & plast)447 void PrsDim_FixRelation::ComputeCirclePosition(
448 	const gp_Circ& gcirc,
449 	gp_Pnt& pos,
450 	Standard_Real& pfirst,
451 	Standard_Real& plast)
452 {
453   // readjust parametres on the circle
454   if (plast > 2*M_PI ) {
455     Standard_Real nbtours = Floor(plast / (2*M_PI));
456     plast -= nbtours*2*M_PI;
457     pfirst -= nbtours*2*M_PI;
458   }
459 
460   if (myAutomaticPosition) {
461     // the point attach is the "middle" of the segment (relatively
462     // to the parametres of start and end vertices of the edge
463 
464     Standard_Real circparam = (pfirst + plast)/2.;
465 
466     if ( !InDomain(pfirst,plast,circparam)) {
467       Standard_Real otherpar = circparam + M_PI;
468       if (otherpar > 2*M_PI) otherpar -= 2*M_PI;
469       circparam = otherpar;
470     }
471 
472     myPntAttach = ElCLib::Value(circparam, gcirc );
473 
474     gp_Vec dir( gcirc.Location().XYZ(), myPntAttach.XYZ() );
475     dir.Normalize();
476     gp_Vec transvec = dir*myArrowSize;
477     pos = myPntAttach.Translated(transvec);
478     myPosition = pos;
479     myAutomaticPosition = Standard_True;
480   } // if (myAutomaticPosition)
481 
482   else {
483     // case if the projection of myPosition is outside of 2
484     // vertices of the edge. In this case the parameter is readjusted
485     // in the valid part of the circle
486     pos = myPosition;
487 
488     Standard_Real circparam = ElCLib::Parameter(gcirc, pos);
489 
490     if ( !InDomain(pfirst,plast,circparam)) {
491       Standard_Real otherpar = circparam + M_PI;
492       if (otherpar > 2*M_PI) otherpar -= 2*M_PI;
493       circparam = otherpar;
494     }
495 
496     myPntAttach = ElCLib::Value(circparam,gcirc);
497   }
498 }
499 
500 //=======================================================================
501 //function : ConnectedEdges
502 //purpose  :
503 //=======================================================================
ConnectedEdges(const TopoDS_Wire & WIRE,const TopoDS_Vertex & V,TopoDS_Edge & E1,TopoDS_Edge & E2)504 Standard_Boolean PrsDim_FixRelation::ConnectedEdges(const TopoDS_Wire& WIRE,
505 						 const TopoDS_Vertex& V,
506 						 TopoDS_Edge& E1,
507 						 TopoDS_Edge& E2)
508 {
509   TopTools_IndexedDataMapOfShapeListOfShape  vertexMap;
510   TopExp::MapShapesAndAncestors (WIRE,TopAbs_VERTEX,TopAbs_EDGE,vertexMap);
511 
512   Standard_Boolean found(Standard_False);
513   TopoDS_Vertex theVertex;
514   for (Standard_Integer i=1; i<=vertexMap.Extent() && !found; i++) {
515     if (vertexMap.FindKey(i).IsSame(V)) {
516      theVertex = TopoDS::Vertex(vertexMap.FindKey(i));
517      found = Standard_True;
518    }
519   }
520   if (!found) {
521     E1.Nullify();
522     E2.Nullify();
523     return Standard_False;
524   }
525 
526   TopTools_ListIteratorOfListOfShape iterator(vertexMap.FindFromKey(theVertex));
527   if (iterator.More()) {
528     E1 = TopoDS::Edge(iterator.Value());
529     BRepAdaptor_Curve curv(E1);
530     iterator.Next();
531   }
532   else {
533     E1.Nullify();
534     return Standard_False;
535   }
536 
537   if (iterator.More()) {
538     E2 = TopoDS::Edge(iterator.Value());
539     BRepAdaptor_Curve curv(E2);
540     iterator.Next();
541   }
542   else {
543     E2.Nullify();
544     return Standard_False;
545   }
546 
547   if (iterator.More()) {
548     E1.Nullify();
549     E2.Nullify();
550     return Standard_False;
551   }
552   return Standard_True;
553 }
554