Salome HOME
3a43b6a1b8c2b07f2392f9bcedbb5b9fee8f0716
[modules/geom.git] / src / GEOMUtils / GEOMUtils_Hatcher.cxx
1 // Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23
24 #include <GEOMUtils_Hatcher.hxx>
25
26 #include <BRep_Tool.hxx>
27 #include <BRepTools.hxx>
28 #include <Geom2d_Line.hxx>
29 #include <Geom2d_TrimmedCurve.hxx>
30 #include <Geom2dAdaptor_Curve.hxx>
31 #include <TopExp_Explorer.hxx>
32 #include <TopoDS.hxx>
33 #include <TopoDS_Edge.hxx>
34 #include <HatchGen_Domain.hxx>
35
36
37 static Standard_Real IntersectorConfusion = 1.e-10; // -8;
38 static Standard_Real IntersectorTangency  = 1.e-10; // -8;
39 static Standard_Real HatcherConfusion2d   = 1.e-8;
40 static Standard_Real HatcherConfusion3d   = 1.e-8;
41 // VTK uses float numbers - Precision::Infinite() is double and
42 // can not be accepted.
43 static float         InfiniteValue        = 1e38;
44
45 //=======================================================================
46 //function : GEOMUtils_Hatcher
47 //purpose  :
48 //=======================================================================
49 GEOMUtils::Hatcher::Hatcher(const TopoDS_Face &theFace)
50 : myHatcher(Geom2dHatch_Intersector (IntersectorConfusion, IntersectorTangency),
51             HatcherConfusion2d, HatcherConfusion3d,
52             Standard_True, Standard_False),
53   myFace   (theFace),
54   myIsDone (Standard_False),
55   myUMin   (0.),
56   myUMax   (0.),
57   myVMin   (0.),
58   myVMax   (0.)
59 {
60   // Get bounds.
61   BRepTools::UVBounds (theFace, myUMin, myUMax, myVMin, myVMax);
62
63   Standard_Boolean InfiniteUMin = Precision::IsNegativeInfinite (myUMin);
64   Standard_Boolean InfiniteUMax = Precision::IsPositiveInfinite (myUMax);
65   Standard_Boolean InfiniteVMin = Precision::IsNegativeInfinite (myVMin);
66   Standard_Boolean InfiniteVMax = Precision::IsPositiveInfinite (myVMax);
67
68   if (InfiniteUMin && InfiniteUMax) {
69     myUMin = - InfiniteValue;
70     myUMax =   InfiniteValue;
71   } else if (InfiniteUMin) {
72     myUMin = myUMax - InfiniteValue;
73   } else if (InfiniteUMax) {
74     myUMax = myUMin + InfiniteValue;
75   }
76
77   if (InfiniteVMin && InfiniteVMax) {
78     myVMin = - InfiniteValue;
79     myVMax =   InfiniteValue;
80   } else if (InfiniteVMin) {
81     myVMin = myVMax - InfiniteValue;
82   } else if (InfiniteVMax) {
83     myVMax = myVMin + InfiniteValue;
84   }
85
86   // Add edges
87   TopExp_Explorer     anExpEdges(theFace, TopAbs_EDGE);
88   const Standard_Real aParamTol = Precision::PConfusion();
89
90   for (; anExpEdges.More(); anExpEdges.Next()) {
91     const TopoDS_Edge& anEdge = TopoDS::Edge (anExpEdges.Current());
92     Standard_Real U1, U2;
93     const Handle(Geom2d_Curve) PCurve =
94       BRep_Tool::CurveOnSurface (anEdge, theFace, U1, U2);
95
96     if (PCurve.IsNull()) {
97       continue;
98     }
99
100     if (U1 == U2) {
101       continue;
102     }
103
104     //-- Test if a TrimmedCurve is necessary
105     if(Abs(PCurve->FirstParameter() - U1) <= aParamTol &&
106        Abs(PCurve->LastParameter() - U2)  <= aParamTol) { 
107       myHatcher.AddElement(PCurve, anEdge.Orientation());
108     } else {
109       if (!PCurve->IsPeriodic()) {
110         Handle(Geom2d_TrimmedCurve) TrimPCurve =
111           Handle(Geom2d_TrimmedCurve)::DownCast(PCurve);
112
113         if (!TrimPCurve.IsNull()) {
114           Handle(Geom2d_Curve) aBasisCurve = TrimPCurve->BasisCurve();
115
116           if (aBasisCurve->FirstParameter() - U1 > aParamTol ||
117               U2 - aBasisCurve->LastParameter()  > aParamTol) {
118             myHatcher.AddElement (PCurve, anEdge.Orientation());
119             return;
120           }
121         } else {
122           if (PCurve->FirstParameter() - U1 > aParamTol) {
123             U1 = PCurve->FirstParameter();
124           }
125           if (U2 - PCurve->LastParameter() > aParamTol) {
126             U2=PCurve->LastParameter();
127           }
128         }
129       }
130
131       Handle (Geom2d_TrimmedCurve) TrimPCurve =
132         new Geom2d_TrimmedCurve (PCurve, U1, U2);
133
134       myHatcher.AddElement (TrimPCurve, anEdge.Orientation());
135     }
136   }
137 }
138
139 //=======================================================================
140 //function : Init
141 //purpose  :
142 //=======================================================================
143 void GEOMUtils::Hatcher::Init(const Standard_Integer theNbIsos)
144 {
145   Init(theNbIsos, theNbIsos);
146 }
147
148 //=======================================================================
149 //function : Init
150 //purpose  :
151 //=======================================================================
152 void GEOMUtils::Hatcher::Init(const Standard_Integer theNbIsoU,
153                               const Standard_Integer theNbIsoV)
154 {
155   // Initialize data.
156   Clear();
157
158   if (theNbIsoU > 0 || theNbIsoV > 0) {
159     Standard_Integer IIso;
160     Standard_Real DeltaU = Abs (myUMax - myUMin);
161     Standard_Real DeltaV = Abs (myVMax - myVMin);
162     Standard_Real confusion = Min (DeltaU, DeltaV) * myHatcher.Confusion3d();
163
164     myHatcher.Confusion3d (confusion);
165
166     if (theNbIsoU > 0) {
167       myUPrm = new TColStd_HArray1OfReal   (1, theNbIsoU);
168       myUInd = new TColStd_HArray1OfInteger(1, theNbIsoU, 0);
169
170       Standard_Real StepU = DeltaU / (Standard_Real) theNbIsoU;
171
172       if (StepU > confusion) {
173         Standard_Real UPrm = myUMin + StepU / 2.;
174         gp_Dir2d Dir (0., 1.);
175
176         for (IIso = 1; IIso <= theNbIsoU; IIso++) {
177           myUPrm->SetValue(IIso, UPrm);
178           gp_Pnt2d Ori (UPrm, 0.);
179           Geom2dAdaptor_Curve HCur (new Geom2d_Line (Ori, Dir));
180           myUInd->SetValue(IIso, myHatcher.AddHatching(HCur));
181           UPrm += StepU;
182         }
183       }
184     }
185
186     if (theNbIsoV > 0) {
187       myVPrm = new TColStd_HArray1OfReal   (1, theNbIsoV);
188       myVInd = new TColStd_HArray1OfInteger(1, theNbIsoV, 0);
189
190       Standard_Real StepV = DeltaV / (Standard_Real) theNbIsoV;
191
192       if (StepV > confusion) {
193         Standard_Real VPrm = myVMin + StepV / 2.;
194         gp_Dir2d Dir (1., 0.);
195
196         for (IIso = 1; IIso <= theNbIsoV; IIso++) {
197           myVPrm->SetValue(IIso, VPrm);
198           gp_Pnt2d Ori (0., VPrm);
199           Geom2dAdaptor_Curve HCur (new Geom2d_Line (Ori, Dir));
200           myVInd->SetValue(IIso, myHatcher.AddHatching(HCur));
201           VPrm += StepV;
202         }
203       }
204     }
205   }
206 }
207
208 //=======================================================================
209 //function : Init
210 //purpose  :
211 //=======================================================================
212 void GEOMUtils::Hatcher::Init(const GeomAbs_IsoType theIsoType,
213                               const Standard_Real   theParameter)
214 {
215   // Initialize data.
216   Clear();
217
218   if (theIsoType == GeomAbs_IsoU || theIsoType == GeomAbs_IsoV) {
219     const Standard_Boolean            isIsoU = (theIsoType == GeomAbs_IsoU);
220     Handle(TColStd_HArray1OfReal)    &aPrm   = (isIsoU ? myUPrm : myVPrm);
221     Handle(TColStd_HArray1OfInteger) &anInd  = (isIsoU ? myUInd : myVInd);
222     Handle(Geom2d_Line) aLine;
223
224     aPrm  = new TColStd_HArray1OfReal   (1, 1);
225     anInd = new TColStd_HArray1OfInteger(1, 1);
226     aPrm->SetValue(1, theParameter);
227
228     if (isIsoU) {
229       // U-isoline
230       gp_Dir2d aDir (0., 1.);
231       gp_Pnt2d anOri(theParameter, 0.);
232
233       aLine = new Geom2d_Line(anOri, aDir);
234     } else {
235       // V-isoline
236       gp_Dir2d aDir (1., 0.);
237       gp_Pnt2d anOri(0., theParameter);
238
239       aLine = new Geom2d_Line(anOri, aDir);
240     }
241
242     Geom2dAdaptor_Curve aGACurve (aLine);
243
244     anInd->SetValue(1, myHatcher.AddHatching(aGACurve));
245   }
246 }
247
248 //=======================================================================
249 //function : Perform
250 //purpose  :
251 //=======================================================================
252 void GEOMUtils::Hatcher::Perform()
253 {
254   myHatcher.Trim();
255
256   // Compute domains.
257   Standard_Integer i;
258   Standard_Integer anIndex;
259
260   if (myUInd.IsNull() == Standard_False) {
261     for (i = myUInd->Lower() ; i <= myUInd->Upper() ; i++) {
262       anIndex = myUInd->Value(i);
263
264       if (anIndex != 0) {
265         if (myHatcher.TrimDone(anIndex) && !myHatcher.TrimFailed(anIndex)) {
266           myHatcher.ComputeDomains(anIndex);
267
268           if (!myIsDone) {
269             myIsDone = (myHatcher.NbDomains(anIndex) > 0);
270           }
271         }
272       }
273     }
274   }
275
276   if (myVInd.IsNull() == Standard_False) {
277     for (i = myVInd->Lower() ; i <= myVInd->Upper() ; i++) {
278       anIndex = myVInd->Value(i);
279
280       if (anIndex != 0) {
281         if (myHatcher.TrimDone(anIndex) && !myHatcher.TrimFailed(anIndex)) {
282           myHatcher.ComputeDomains(anIndex);
283
284           if (!myIsDone) {
285             myIsDone = (myHatcher.NbDomains(anIndex) > 0);
286           }
287         }
288       }
289     }
290   }
291 }
292
293 //=======================================================================
294 //function : GetNbDomains
295 //purpose  :
296 //=======================================================================
297 Standard_Integer GEOMUtils::Hatcher::GetNbDomains
298               (const Standard_Integer theHatchingIndex) const
299 {
300   Standard_Integer aResult = -1;
301
302   if (myIsDone && myHatcher.IsDone(theHatchingIndex)) {
303     aResult = myHatcher.NbDomains(theHatchingIndex);
304   }
305
306   return aResult;
307 }
308
309 //=======================================================================
310 //function : GetDomain
311 //purpose  :
312 //=======================================================================
313 Standard_Boolean GEOMUtils::Hatcher::GetDomain
314                            (const Standard_Integer  theHatchingIndex,
315                             const Standard_Integer  theDomainIndex,
316                                   Standard_Real    &theParam1,
317                                   Standard_Real    &theParam2) const
318 {
319   Standard_Boolean isOK = Standard_False;
320
321   if (theDomainIndex > 0) {
322     const Standard_Integer aNbDomains = GetNbDomains(theHatchingIndex);
323
324     if (theDomainIndex <= aNbDomains) {
325       const HatchGen_Domain& aDomain =
326         myHatcher.Domain (theHatchingIndex, theDomainIndex);
327
328       if (aDomain.HasFirstPoint()) {
329         theParam1 = aDomain.FirstPoint().Parameter();
330       } else {
331         theParam1 = myVMin - InfiniteValue;
332       }
333
334       if (aDomain.HasSecondPoint()) {
335         theParam2 = aDomain.SecondPoint().Parameter();
336       } else {
337         theParam2 = myVMax + InfiniteValue;
338       }
339
340       isOK = Standard_True;
341     }
342   }
343
344   return isOK;
345 }
346
347 //=======================================================================
348 //function : IsDomainInfinite
349 //purpose  :
350 //=======================================================================
351 Standard_Boolean GEOMUtils::Hatcher::IsDomainInfinite
352                            (const Standard_Integer  theHatchingIndex,
353                             const Standard_Integer  theDomainIndex) const
354 {
355   Standard_Boolean isInfinite = Standard_False;
356
357   if (theDomainIndex > 0) {
358     const Standard_Integer aNbDomains = GetNbDomains(theHatchingIndex);
359
360     if (theDomainIndex <= aNbDomains) {
361       const HatchGen_Domain& aDomain =
362         myHatcher.Domain (theHatchingIndex, theDomainIndex);
363
364       if (!aDomain.HasFirstPoint() || !aDomain.HasSecondPoint()) {
365         isInfinite = Standard_True;
366       }
367     }
368   }
369
370   return isInfinite;
371 }
372
373 //=======================================================================
374 //function : GetHatching
375 //purpose  :
376 //=======================================================================
377 const Handle(Geom2d_Curve) &GEOMUtils::Hatcher::GetHatching
378                       (const Standard_Integer theHatchingIndex) const
379 {
380   const Geom2dAdaptor_Curve &aGACurve =
381     myHatcher.HatchingCurve(theHatchingIndex);
382
383   return aGACurve.Curve();
384 }
385
386 //=======================================================================
387 //function : Clear
388 //purpose  :
389 //=======================================================================
390 void GEOMUtils::Hatcher::Clear()
391 {
392   myIsDone = Standard_False;
393   myUPrm.Nullify();
394   myVPrm.Nullify();
395   myUInd.Nullify();
396   myVInd.Nullify();
397   myHatcher.ClrHatchings();
398 }