0033084: Visualization - Cylindrical prism is selectable only by its base when extrud...
[occt.git] / src / SelectMgr / SelectMgr.cxx
1 // Copyright (c) 2020 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #include <SelectMgr.hxx>
15
16 #include <Geom_Circle.hxx>
17 #include <Graphic3d_ArrayOfPoints.hxx>
18 #include <Graphic3d_AspectMarker3d.hxx>
19 #include <Poly_Triangulation.hxx>
20 #include <Prs3d.hxx>
21 #include <Prs3d_LineAspect.hxx>
22 #include <Prs3d_NListOfSequenceOfPnt.hxx>
23 #include <TColgp_HArray1OfPnt.hxx>
24 #include <TColgp_SequenceOfPnt.hxx>
25 #include <Select3D_SensitiveBox.hxx>
26 #include <Select3D_SensitiveCylinder.hxx>
27 #include <Select3D_SensitiveEntity.hxx>
28 #include <Select3D_SensitiveFace.hxx>
29 #include <Select3D_SensitivePoint.hxx>
30 #include <Select3D_SensitiveSegment.hxx>
31 #include <Select3D_SensitiveTriangle.hxx>
32 #include <Select3D_SensitiveTriangulation.hxx>
33 #include <Select3D_SensitiveWire.hxx>
34 #include <SelectMgr_Selection.hxx>
35
36 namespace
37 {
38   //! Compute polyline of shrunk triangle.
39   static Handle(TColgp_HSequenceOfPnt) shrunkTriangle (const gp_Pnt* thePnts,
40                                                        const gp_XYZ& theCenter)
41   {
42     const gp_XYZ aV1 = theCenter + (thePnts[0].XYZ() - theCenter) * 0.9;
43     const gp_XYZ aV2 = theCenter + (thePnts[1].XYZ() - theCenter) * 0.9;
44     const gp_XYZ aV3 = theCenter + (thePnts[2].XYZ() - theCenter) * 0.9;
45     Handle(TColgp_HSequenceOfPnt) aPoints = new TColgp_HSequenceOfPnt();
46     aPoints->Append (aV1);
47     aPoints->Append (aV2);
48     aPoints->Append (aV3);
49     aPoints->Append (aV1);
50     return aPoints;
51   }
52
53   //! Fill in triangulation polylines.
54   static void addTriangulation (Prs3d_NListOfSequenceOfPnt& theSeqLines,
55                                 Prs3d_NListOfSequenceOfPnt& theSeqFree,
56                                 const Handle(Select3D_SensitiveTriangulation)& theTri,
57                                 const gp_Trsf& theLoc)
58   {
59     gp_Trsf aTrsf = theLoc;
60     if (theTri->HasInitLocation())
61     {
62       aTrsf = theLoc * theTri->GetInitLocation();
63     }
64     const Handle(Poly_Triangulation)& aPolyTri = theTri->Triangulation();
65     for (Standard_Integer aTriIter = 1; aTriIter <= aPolyTri->NbTriangles(); ++aTriIter)
66     {
67       const Poly_Triangle& aTri = aPolyTri->Triangle (aTriIter);
68       const gp_Pnt aPnts[3] =
69       {
70         aPolyTri->Node (aTri (1)).Transformed (aTrsf),
71         aPolyTri->Node (aTri (2)).Transformed (aTrsf),
72         aPolyTri->Node (aTri (3)).Transformed (aTrsf)
73       };
74       const gp_XYZ aCenter = (aPnts[0].XYZ() + aPnts[1].XYZ() + aPnts[2].XYZ()) / 3.0;
75       theSeqLines.Append (shrunkTriangle (aPnts, aCenter));
76     }
77
78     Handle(TColgp_HSequenceOfPnt) aPoints = new TColgp_HSequenceOfPnt();
79     Prs3d::AddFreeEdges (*aPoints, aPolyTri, aTrsf);
80     if (!aPoints->IsEmpty())
81     {
82       theSeqFree.Append (aPoints);
83     }
84   }
85
86   //! Fill in bounding box polylines.
87   static void addBoundingBox (Prs3d_NListOfSequenceOfPnt& theSeqLines,
88                               const Handle(Select3D_SensitiveBox)& theSensBox,
89                               const gp_Trsf& theLoc)
90   {
91     Graphic3d_Vec3d aMin, aMax;
92     theSensBox->Box().Get (aMin.x(), aMin.y(), aMin.z(), aMax.x(), aMax.y(), aMax.z());
93     gp_Pnt aPnts[8] =
94     {
95       gp_Pnt(aMin.x(), aMin.y(), aMin.z()),
96       gp_Pnt(aMax.x(), aMin.y(), aMin.z()),
97       gp_Pnt(aMax.x(), aMax.y(), aMin.z()),
98       gp_Pnt(aMin.x(), aMax.y(), aMin.z()),
99       gp_Pnt(aMin.x(), aMin.y(), aMax.z()),
100       gp_Pnt(aMax.x(), aMin.y(), aMax.z()),
101       gp_Pnt(aMax.x(), aMax.y(), aMax.z()),
102       gp_Pnt(aMin.x(), aMax.y(), aMax.z())
103     };
104     for (Standard_Integer aPntIter = 0; aPntIter <= 7; ++aPntIter)
105     {
106       aPnts[aPntIter].Transform (theLoc);
107     }
108
109     {
110       Handle(TColgp_HSequenceOfPnt) aPoints = new TColgp_HSequenceOfPnt();
111       for (Standard_Integer i = 0; i < 4; ++i)
112       {
113         aPoints->Append (aPnts[i]);
114       }
115       aPoints->Append (aPnts[0]);
116       theSeqLines.Append (aPoints);
117     }
118     {
119       Handle(TColgp_HSequenceOfPnt) aPoints = new TColgp_HSequenceOfPnt();
120       for (Standard_Integer i = 4; i < 8; i++)
121       {
122         aPoints->Append (aPnts[i]);
123       }
124       aPoints->Append (aPnts[4]);
125       theSeqLines.Append (aPoints);
126     }
127     for (Standard_Integer i = 0; i < 4; i++)
128     {
129       Handle(TColgp_HSequenceOfPnt) aPoints = new TColgp_HSequenceOfPnt();
130       aPoints->Append (aPnts[i]);
131       aPoints->Append (aPnts[i+4]);
132       theSeqLines.Append (aPoints);
133     }
134   }
135
136   //! Fill in cylinder polylines.
137   static void addCylinder (Prs3d_NListOfSequenceOfPnt& theSeqLines,
138                            const Handle(Select3D_SensitiveCylinder)& theSensCyl)
139   {
140     Handle(TColgp_HSequenceOfPnt) aVertLines[2];
141     aVertLines[0] = new TColgp_HSequenceOfPnt();
142     aVertLines[1] = new TColgp_HSequenceOfPnt();
143     const gp_Trsf& aTrsf = theSensCyl->Transformation();
144     const Standard_Real aHeight = theSensCyl->Height();
145     const Standard_Real anUStep = 0.1;
146
147     for (int aCircNum = 0; aCircNum < 3; aCircNum++)
148     {
149       Standard_Real aRadius = 0.5 * (2 - aCircNum) * theSensCyl->BottomRadius()
150                             + 0.5 * aCircNum * theSensCyl->TopRadius();
151       Geom_Circle aGeom (gp_Ax2(), aRadius);
152       Handle(TColgp_HSequenceOfPnt) aPoints = new TColgp_HSequenceOfPnt();
153       gp_XYZ aVec (0, 0, aHeight * 0.5 * aCircNum);
154
155       if (aCircNum != 1)
156       {
157         aVertLines[0]->Append (gp_Pnt(aGeom.Value (0).Coord() + aVec).Transformed (aTrsf));
158         aVertLines[1]->Append (gp_Pnt(aGeom.Value (M_PI).Coord() + aVec).Transformed (aTrsf));
159       }
160
161       for (Standard_Real anU = 0.0f; anU < (2.0 * M_PI + anUStep); anU += anUStep)
162       {
163         gp_Pnt aCircPnt = aGeom.Value (anU).Coord() + aVec;
164         aCircPnt.Transform (aTrsf);
165         aPoints->Append (aCircPnt);
166       }
167       theSeqLines.Append (aPoints);
168     }
169     theSeqLines.Append (aVertLines[0]);
170     theSeqLines.Append (aVertLines[1]);
171   }
172 }
173
174 //=======================================================================
175 //function : ComputeSensitivePrs
176 //purpose  :
177 //=======================================================================
178 void SelectMgr::ComputeSensitivePrs (const Handle(Graphic3d_Structure)& thePrs,
179                                      const Handle(SelectMgr_Selection)& theSel,
180                                      const gp_Trsf& theLoc,
181                                      const Handle(Graphic3d_TransformPers)& theTrsfPers)
182 {
183   thePrs->SetTransformPersistence (theTrsfPers);
184
185   Prs3d_NListOfSequenceOfPnt aSeqLines, aSeqFree;
186   TColgp_SequenceOfPnt aSeqPoints;
187   for (NCollection_Vector<Handle(SelectMgr_SensitiveEntity)>::Iterator aSelEntIter (theSel->Entities()); aSelEntIter.More(); aSelEntIter.Next())
188   {
189     const Handle(Select3D_SensitiveEntity)& anEnt = aSelEntIter.Value()->BaseSensitive();
190     if (Handle(Select3D_SensitiveBox) aSensBox = Handle(Select3D_SensitiveBox)::DownCast (anEnt))
191     {
192       addBoundingBox (aSeqLines, aSensBox, theLoc);
193     }
194     else if (Handle(Select3D_SensitiveCylinder) aSensCyl = Handle(Select3D_SensitiveCylinder)::DownCast (anEnt))
195     {
196       addCylinder (aSeqLines, aSensCyl);
197     }
198     else if (Handle(Select3D_SensitiveFace) aFace = Handle(Select3D_SensitiveFace)::DownCast(anEnt))
199     {
200       Handle(TColgp_HArray1OfPnt) aSensPnts;
201       aFace->GetPoints (aSensPnts);
202       Handle(TColgp_HSequenceOfPnt) aPoints = new TColgp_HSequenceOfPnt();
203       for (TColgp_HArray1OfPnt::Iterator aPntIter (*aSensPnts); aPntIter.More(); aPntIter.Next())
204       {
205         aPoints->Append (aPntIter.Value().Transformed (theLoc));
206       }
207       aSeqLines.Append (aPoints);
208     }
209     else if (Handle(Select3D_SensitivePoly) aSensPoly = Handle(Select3D_SensitivePoly)::DownCast (anEnt))
210     {
211       Standard_Integer aFrom = 0, aTo = 0;
212       aSensPoly->ArrayBounds (aFrom, aTo);
213       Handle(TColgp_HSequenceOfPnt) aPoints = new TColgp_HSequenceOfPnt();
214       for (Standard_Integer aPntIter = aFrom; aPntIter <= aTo; ++aPntIter)
215       {
216         aPoints->Append (aSensPoly->GetPoint3d (aPntIter).Transformed (theLoc));
217       }
218       aSeqLines.Append (aPoints);
219     }
220     else if (Handle(Select3D_SensitiveWire) aWire = Handle(Select3D_SensitiveWire)::DownCast(anEnt))
221     {
222       const NCollection_Vector<Handle(Select3D_SensitiveEntity)>& anEntities = aWire->GetEdges();
223       for (NCollection_Vector<Handle(Select3D_SensitiveEntity)>::Iterator aSubIter (anEntities); aSubIter.More(); aSubIter.Next())
224       {
225         const Handle(Select3D_SensitiveEntity)& aSubEnt = aSubIter.Value();
226         if (Handle(Select3D_SensitiveSegment) aSensSeg = Handle(Select3D_SensitiveSegment)::DownCast (aSubEnt))
227         {
228           Handle(TColgp_HSequenceOfPnt) aPoints = new TColgp_HSequenceOfPnt();
229           aPoints->Append (aSensSeg->StartPoint().Transformed (theLoc));
230           aPoints->Append (aSensSeg->EndPoint()  .Transformed (theLoc));
231           aSeqLines.Append (aPoints);
232         }
233         else if (Handle(Select3D_SensitivePoly) aSubSensPoly = Handle(Select3D_SensitivePoly)::DownCast (aSubEnt))
234         {
235           Standard_Integer aFrom = 0, aTo = 0;
236           aSubSensPoly->ArrayBounds (aFrom, aTo);
237           Handle(TColgp_HSequenceOfPnt) aPoints = new TColgp_HSequenceOfPnt();
238           for (Standard_Integer aPntIter = aFrom; aPntIter <= aTo; ++aPntIter)
239           {
240             aPoints->Append (aSubSensPoly->GetPoint3d (aPntIter).Transformed (theLoc));
241           }
242           aSeqLines.Append (aPoints);
243         }
244       }
245     }
246     else if (Handle(Select3D_SensitiveSegment) aSensSeg = Handle(Select3D_SensitiveSegment)::DownCast(anEnt))
247     {
248       Handle(TColgp_HSequenceOfPnt) aPoints = new TColgp_HSequenceOfPnt();
249       aPoints->Append (aSensSeg->StartPoint().Transformed (theLoc));
250       aPoints->Append (aSensSeg->EndPoint()  .Transformed (theLoc));
251       aSeqLines.Append (aPoints);
252     }
253     else if (Handle(Select3D_SensitivePoint) aSensPnt = Handle(Select3D_SensitivePoint)::DownCast(anEnt))
254     {
255       aSeqPoints.Append (aSensPnt->Point().Transformed (theLoc));
256     }
257     else if (Handle(Select3D_SensitiveTriangulation) aSensTri = Handle(Select3D_SensitiveTriangulation)::DownCast (anEnt))
258     {
259       addTriangulation (aSeqLines, aSeqFree, aSensTri, theLoc);
260     }
261     else if (Handle(Select3D_SensitiveTriangle) aSensTri1 = Handle(Select3D_SensitiveTriangle)::DownCast(anEnt))
262     {
263       gp_Pnt aPnts[3];
264       aSensTri1->Points3D (aPnts[0], aPnts[1], aPnts[2]);
265       aPnts[0].Transform (theLoc);
266       aPnts[1].Transform (theLoc);
267       aPnts[2].Transform (theLoc);
268       aSeqLines.Append (shrunkTriangle (aPnts, aSensTri1->Center3D().XYZ()));
269     }
270   }
271
272   if (!aSeqPoints.IsEmpty())
273   {
274     Handle(Graphic3d_ArrayOfPoints) anArrayOfPoints = new Graphic3d_ArrayOfPoints (aSeqPoints.Size());
275     for (TColgp_SequenceOfPnt::Iterator aPntIter (aSeqPoints); aPntIter.More(); aPntIter.Next())
276     {
277       anArrayOfPoints->AddVertex (aPntIter.Value());
278     }
279
280     Handle(Graphic3d_Group) aSensPntGroup = thePrs->NewGroup();
281     aSensPntGroup->SetPrimitivesAspect (new Graphic3d_AspectMarker3d (Aspect_TOM_O_PLUS, Quantity_NOC_INDIANRED3, 2.0));
282     aSensPntGroup->AddPrimitiveArray (anArrayOfPoints);
283   }
284   if (!aSeqLines.IsEmpty())
285   {
286     Prs3d::AddPrimitivesGroup (thePrs, new Prs3d_LineAspect (Quantity_NOC_AQUAMARINE1, Aspect_TOL_DASH, 1.0), aSeqLines);
287   }
288   if (!aSeqFree.IsEmpty())
289   {
290     Prs3d::AddPrimitivesGroup (thePrs, new Prs3d_LineAspect (Quantity_NOC_GREEN, Aspect_TOL_SOLID, 2.0), aSeqFree);
291   }
292 }