b311480e |
1 | // Created on: 1998-08-04 |
2 | // Created by: Pavel DURANDIN |
3 | // Copyright (c) 1998-1999 Matra Datavision |
973c2be1 |
4 | // Copyright (c) 1999-2014 OPEN CASCADE SAS |
b311480e |
5 | // |
973c2be1 |
6 | // This file is part of Open CASCADE Technology software library. |
b311480e |
7 | // |
d5f74e42 |
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 |
973c2be1 |
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. |
b311480e |
13 | // |
973c2be1 |
14 | // Alternatively, this file may be used under the terms of Open CASCADE |
15 | // commercial license or contractual agreement. |
b311480e |
16 | |
7fd59977 |
17 | // 25.12.98 pdn renaming of ShapeAnalysis_FreeBounds and ShapeAnalysis_Wire methods |
18 | //szv#4 S4163 |
19 | |
42cf5bc1 |
20 | #include <BRep_Builder.hxx> |
21 | #include <BRepTools_WireExplorer.hxx> |
22 | #include <Geom_Curve.hxx> |
23 | #include <GeomAPI_ProjectPointOnCurve.hxx> |
24 | #include <gp_Pnt.hxx> |
25 | #include <gp_Vec.hxx> |
26 | #include <gp_XYZ.hxx> |
27 | #include <Precision.hxx> |
7fd59977 |
28 | #include <ShapeAnalysis_Edge.hxx> |
7fd59977 |
29 | #include <ShapeAnalysis_FreeBoundData.hxx> |
42cf5bc1 |
30 | #include <ShapeAnalysis_FreeBounds.hxx> |
31 | #include <ShapeAnalysis_FreeBoundsProperties.hxx> |
32 | #include <ShapeAnalysis_Wire.hxx> |
7fd59977 |
33 | #include <ShapeExtend_Explorer.hxx> |
34 | #include <ShapeExtend_WireData.hxx> |
7fd59977 |
35 | #include <TopoDS.hxx> |
36 | #include <TopoDS_Edge.hxx> |
42cf5bc1 |
37 | #include <TopoDS_Shape.hxx> |
38 | #include <TopoDS_Wire.hxx> |
7fd59977 |
39 | #include <TopTools_HSequenceOfShape.hxx> |
40 | |
7fd59977 |
41 | #define NbControl 23 |
42 | |
43 | static void ContourProperties(TopoDS_Wire wire, |
44 | Standard_Real& countourArea, |
45 | Standard_Real& countourLength) |
46 | { |
47 | Standard_Integer nbe = 0; |
48 | Standard_Real length = 0.0; |
49 | gp_XYZ area(.0,.0,.0); |
50 | gp_XYZ prev, cont; |
51 | |
52 | for (BRepTools_WireExplorer exp(wire); exp.More(); exp.Next()) { |
53 | TopoDS_Edge Edge = exp.Current(); nbe++; |
54 | |
55 | Standard_Real First, Last; |
56 | Handle(Geom_Curve) c3d; |
57 | ShapeAnalysis_Edge sae; |
58 | if (!sae.Curve3d(Edge,c3d,First,Last)) continue; |
59 | |
60 | Standard_Integer ibeg = 0; |
61 | if ( nbe == 1 ) { |
62 | gp_Pnt pntIni = c3d->Value(First); |
63 | prev = pntIni.XYZ(); |
64 | cont = prev; |
65 | ibeg = 1; |
66 | } |
67 | |
68 | for ( Standard_Integer i = ibeg; i < NbControl; i++) { |
69 | Standard_Real prm = ((NbControl-1-i)*First + i*Last)/(NbControl-1); |
70 | gp_Pnt pntCurr = c3d->Value(prm); |
71 | gp_XYZ curr = pntCurr.XYZ(); |
72 | gp_XYZ delta = curr - prev; |
73 | length += delta.Modulus(); |
74 | area += curr ^ prev; |
75 | prev = curr; |
76 | } |
77 | } |
78 | |
79 | area += cont ^ prev; |
80 | countourArea = area.Modulus()/2; |
81 | countourLength = length; |
82 | } |
83 | |
84 | //======================================================================= |
85 | //function : ShapeAnalysis_FreeBoundsProperties |
86 | //purpose : Empty constructor |
87 | //======================================================================= |
88 | |
89 | ShapeAnalysis_FreeBoundsProperties::ShapeAnalysis_FreeBoundsProperties() |
90 | { |
91 | myClosedFreeBounds = new ShapeAnalysis_HSequenceOfFreeBounds(); |
92 | myOpenFreeBounds = new ShapeAnalysis_HSequenceOfFreeBounds(); |
93 | myTolerance = 0.; |
94 | } |
95 | |
96 | //======================================================================= |
97 | //function : ShapeAnalysis_FreeBoundsProperties |
98 | //purpose : Creates the object and calls corresponding Init. |
99 | // <shape> should be a compound of faces. |
100 | //======================================================================= |
101 | |
102 | ShapeAnalysis_FreeBoundsProperties::ShapeAnalysis_FreeBoundsProperties(const TopoDS_Shape& shape, |
103 | const Standard_Real tolerance, |
104 | const Standard_Boolean splitclosed, |
105 | const Standard_Boolean splitopen) |
106 | { |
107 | myClosedFreeBounds = new ShapeAnalysis_HSequenceOfFreeBounds(); |
108 | myOpenFreeBounds = new ShapeAnalysis_HSequenceOfFreeBounds(); |
109 | Init(shape, tolerance, splitclosed, splitopen); |
110 | } |
111 | |
112 | //======================================================================= |
113 | //function : ShapeAnalysis_FreeBoundsProperties |
114 | //purpose : Creates the object and calls corresponding Init. |
115 | // <shape> should be a compound of shells. |
116 | //======================================================================= |
117 | |
118 | ShapeAnalysis_FreeBoundsProperties::ShapeAnalysis_FreeBoundsProperties(const TopoDS_Shape& shape, |
119 | const Standard_Boolean splitclosed, |
120 | const Standard_Boolean splitopen) |
121 | { |
122 | myClosedFreeBounds = new ShapeAnalysis_HSequenceOfFreeBounds(); |
123 | myOpenFreeBounds = new ShapeAnalysis_HSequenceOfFreeBounds(); |
124 | myTolerance =0.; |
125 | Init(shape, splitclosed, splitopen); |
126 | } |
127 | |
128 | //======================================================================= |
129 | //function : Init |
130 | //purpose : Initializes the object with given parameters. |
131 | // <shape> should be a compound of faces. |
132 | //======================================================================= |
133 | |
134 | void ShapeAnalysis_FreeBoundsProperties::Init(const TopoDS_Shape& shape, |
135 | const Standard_Real tolerance, |
136 | const Standard_Boolean splitclosed, |
137 | const Standard_Boolean splitopen) |
138 | { |
139 | Init(shape, splitclosed, splitopen); |
140 | myTolerance = tolerance; |
141 | } |
142 | |
143 | |
144 | //======================================================================= |
145 | //function : Init |
146 | //purpose : Initializes the object with given parameters. |
147 | // <shape> should be a compound of shells. |
148 | //======================================================================= |
149 | |
150 | void ShapeAnalysis_FreeBoundsProperties::Init(const TopoDS_Shape& shape, |
151 | const Standard_Boolean splitclosed, |
152 | const Standard_Boolean splitopen) |
153 | { |
154 | myShape = shape; |
155 | mySplitClosed = splitclosed; |
156 | mySplitOpen = splitopen; |
157 | } |
158 | |
159 | |
160 | //======================================================================= |
161 | //function : Perform |
162 | //purpose : Builds and analyzes free bounds of the shape. |
163 | // First calls ShapeAnalysis_FreeBounds for building free |
164 | // bounds. |
165 | // Then on each free bound computes its properties: |
166 | // - area of the contour, |
167 | // - perimeter of the contour, |
168 | // - ratio of average length to average width of the contour, |
169 | // - average width of contour, |
170 | // - notches on the contour and for each notch |
171 | // - maximum width of the notch. |
172 | //returns: True - if no fails and free bounds are found, |
173 | // False - if fail or no free bounds are found |
174 | //======================================================================= |
175 | |
176 | Standard_Boolean ShapeAnalysis_FreeBoundsProperties::Perform() |
177 | { |
178 | Standard_Boolean result = Standard_False; |
179 | result |= DispatchBounds(); |
180 | result |= CheckNotches(); |
181 | result |= CheckContours(); |
182 | return result; |
183 | } |
184 | |
185 | |
186 | //======================================================================= |
187 | //function : DispatchBounds |
188 | //purpose : |
189 | //======================================================================= |
190 | |
191 | Standard_Boolean ShapeAnalysis_FreeBoundsProperties::DispatchBounds() |
192 | { |
193 | if (!IsLoaded()) return Standard_False; |
194 | |
195 | TopoDS_Compound tmpClosedBounds, tmpOpenBounds; |
196 | if ( myTolerance > 0.) { |
197 | ShapeAnalysis_FreeBounds safb(myShape, myTolerance, mySplitClosed, mySplitOpen); |
198 | tmpClosedBounds = safb.GetClosedWires(); |
199 | tmpOpenBounds = safb.GetOpenWires(); |
200 | } |
201 | else { |
202 | ShapeAnalysis_FreeBounds safb(myShape, mySplitClosed, mySplitOpen); |
203 | tmpClosedBounds = safb.GetClosedWires(); |
204 | tmpOpenBounds = safb.GetOpenWires(); |
205 | } |
206 | |
207 | ShapeExtend_Explorer shexpl; |
208 | Handle(TopTools_HSequenceOfShape) tmpSeq = shexpl.SeqFromCompound(tmpClosedBounds,Standard_False); |
209 | Standard_Integer i; // svv Jan11 2000 : porting on DEC |
210 | for (i = 1; i<=tmpSeq->Length(); i++) { |
211 | TopoDS_Wire wire = TopoDS::Wire(tmpSeq->Value(i)); |
212 | Handle(ShapeAnalysis_FreeBoundData) fbData= new ShapeAnalysis_FreeBoundData() ; |
213 | fbData->SetFreeBound(wire); |
214 | myClosedFreeBounds -> Append(fbData); |
215 | } |
216 | |
217 | Handle(TopTools_HSequenceOfShape) tmpSeq2 = shexpl.SeqFromCompound(tmpOpenBounds,Standard_False); |
218 | for(i = 1; i<=tmpSeq2->Length(); i++) { |
219 | TopoDS_Wire wire = TopoDS::Wire(tmpSeq2->Value(i)); |
220 | Handle(ShapeAnalysis_FreeBoundData) fbData = new ShapeAnalysis_FreeBoundData; |
221 | fbData->SetFreeBound(wire); |
222 | myOpenFreeBounds -> Append(fbData); |
223 | } |
224 | |
225 | return Standard_True; |
226 | } |
227 | |
228 | |
229 | //======================================================================= |
230 | //function : CheckNotches |
231 | //purpose : |
232 | //======================================================================= |
233 | |
234 | Standard_Boolean ShapeAnalysis_FreeBoundsProperties::CheckNotches(const Standard_Real prec) |
235 | { |
236 | Standard_Integer i; // svv Jan11 2000 : porting on DEC |
237 | for(i = 1; i <= myClosedFreeBounds->Length(); i++) { |
238 | Handle(ShapeAnalysis_FreeBoundData) fbData = myClosedFreeBounds->Value(i); |
239 | CheckNotches(fbData, prec); |
240 | } |
241 | for( i = 1; i <= myOpenFreeBounds->Length(); i++) { |
242 | Handle(ShapeAnalysis_FreeBoundData) fbData = myOpenFreeBounds->Value(i); |
243 | CheckNotches(fbData, prec); |
244 | } |
245 | |
246 | return Standard_True; |
247 | } |
248 | |
249 | //======================================================================= |
250 | //function : CheckNotches |
251 | //purpose : |
252 | //======================================================================= |
253 | |
254 | Standard_Boolean ShapeAnalysis_FreeBoundsProperties::CheckNotches(Handle(ShapeAnalysis_FreeBoundData)& fbData, |
255 | const Standard_Real prec) |
256 | { |
257 | ShapeExtend_WireData swd(fbData->FreeBound()); |
258 | if (swd.NbEdges() > 1) |
259 | for (Standard_Integer j=1; j <= swd.NbEdges(); j++) { |
260 | TopoDS_Wire notch; |
261 | Standard_Real dMax; |
262 | if (CheckNotches(fbData->FreeBound(), j, notch, dMax, prec)) |
263 | fbData->AddNotch(notch, dMax); |
264 | } |
265 | |
266 | return Standard_True; |
267 | } |
268 | |
269 | //======================================================================= |
270 | //function : CheckContours |
271 | //purpose : |
272 | //======================================================================= |
273 | |
274 | Standard_Boolean ShapeAnalysis_FreeBoundsProperties::CheckContours(const Standard_Real prec) |
275 | { |
276 | Standard_Boolean status = Standard_False; |
277 | Standard_Integer i; // svv Jan11 2000 : porting on DEC |
278 | for( i = 1; i <= myClosedFreeBounds->Length(); i++) { |
279 | Handle(ShapeAnalysis_FreeBoundData) fbData = myClosedFreeBounds->Value(i); |
280 | status |= FillProperties(fbData,prec); |
281 | } |
282 | for ( i = 1; i <= myOpenFreeBounds->Length(); i++) { |
283 | Handle(ShapeAnalysis_FreeBoundData) fbData = myOpenFreeBounds->Value(i); |
284 | status |= FillProperties(fbData,prec); |
285 | } |
286 | |
287 | return status; |
288 | } |
289 | |
290 | |
291 | //======================================================================= |
292 | //function : CheckNotches |
293 | //purpose : |
294 | //======================================================================= |
295 | |
296 | Standard_Boolean ShapeAnalysis_FreeBoundsProperties::CheckNotches(const TopoDS_Wire& wire, |
297 | const Standard_Integer num, |
298 | TopoDS_Wire& notch, |
299 | Standard_Real& distMax, |
300 | const Standard_Real /*prec*/) |
301 | { |
302 | Standard_Real tol = Max ( myTolerance, Precision::Confusion()); |
303 | Handle(ShapeExtend_WireData) wdt = new ShapeExtend_WireData(wire); |
304 | BRep_Builder B; |
305 | B.MakeWire(notch); |
306 | |
307 | if ( (num <= 0)||(num > wdt->NbEdges()) ) return Standard_False; |
308 | |
309 | Standard_Integer n1 = ( num > 0 ? num : wdt->NbEdges() ); |
310 | Standard_Integer n2 = ( n1 < wdt->NbEdges() ? n1+1 : 1 ); |
311 | |
312 | TopoDS_Edge E1 = wdt->Edge(n1); |
313 | B.Add(notch,E1); |
314 | |
315 | Handle(ShapeAnalysis_Wire) saw = new ShapeAnalysis_Wire; |
316 | saw->Load(wdt); |
317 | saw->SetPrecision(myTolerance); |
318 | if ( saw->CheckSmall( n2, tol ) ) { |
319 | B.Add(notch,wdt->Edge(n2)); |
320 | n2 = ( n2 < wdt->NbEdges() ? n2+1 : 1); |
321 | } |
322 | |
323 | TopoDS_Edge E2 = wdt->Edge(n2); |
324 | B.Add(notch,E2); |
325 | |
326 | Standard_Real First1, Last1, First2, Last2; |
327 | Handle(Geom_Curve) c3d1, c3d2; |
328 | ShapeAnalysis_Edge sae; |
329 | //szv#4:S4163:12Mar99 optimized |
330 | if ( !sae.Curve3d(E1, c3d1, First1, Last1) || |
331 | !sae.Curve3d(E2, c3d2, First2, Last2) ) return Standard_False; |
332 | |
333 | gp_Pnt pnt; |
334 | gp_Vec vec1, vec2; |
335 | c3d1->D1(Last1, pnt, vec1); |
336 | c3d2->D1(First2,pnt, vec2); |
337 | if ( E1.Orientation() == TopAbs_REVERSED ) vec1.Reverse(); |
338 | if ( E2.Orientation() == TopAbs_REVERSED ) vec2.Reverse(); |
339 | |
340 | Standard_Real angl = Abs( vec1.Angle(vec2)); |
c6541a0c |
341 | if (angl > 0.95*M_PI) { |
7fd59977 |
342 | distMax = .0; |
343 | for (Standard_Integer i = 0; i < NbControl; i++) { |
344 | Standard_Real prm = ((NbControl-1-i)*First1 + i*Last1)/(NbControl-1); |
345 | gp_Pnt pntCurr = c3d1->Value(prm); |
346 | |
347 | Standard_Real p1, p2; |
348 | if ( First2 < Last2 ) { |
349 | p1 = First2; |
350 | p2 = Last2; |
351 | } |
352 | else { |
353 | p1 = Last2; |
354 | p2 = First2; |
355 | } |
356 | |
357 | //szv#4:S4163:12Mar99 warning |
358 | GeomAPI_ProjectPointOnCurve ppc(pntCurr, c3d2, p1, p2); |
359 | Standard_Real newDist = (ppc.NbPoints() ? ppc.LowerDistance() : 0); |
360 | if ( newDist > distMax ) distMax = newDist; |
361 | } |
362 | |
363 | return Standard_True; |
364 | } |
365 | |
366 | return Standard_False; |
367 | } |
368 | |
369 | |
370 | //======================================================================= |
371 | //function : FillProperties |
372 | //purpose : |
373 | //======================================================================= |
374 | |
375 | Standard_Boolean ShapeAnalysis_FreeBoundsProperties::FillProperties(Handle(ShapeAnalysis_FreeBoundData)& fbData, |
376 | const Standard_Real /*prec*/) |
377 | { |
378 | Standard_Real area, length; |
379 | ContourProperties(fbData->FreeBound(), area, length); |
380 | |
381 | Standard_Real r = 0; |
382 | Standard_Real aver = 0; |
383 | |
384 | if ( length != 0. ) { //szv#4:S4163:12Mar99 anti-exception |
385 | Standard_Real k = area /(length*length); //szv#4:S4163:12Mar99 |
386 | //szv#4:S4163:12Mar99 optimized |
387 | if ( k != 0. ) { //szv#4:S4163:12Mar99 anti-exception |
388 | Standard_Real aux = 1. - 16.*k; |
389 | if ( aux >= 0.) { |
390 | r = (1. + sqrt(aux))/(8.*k); |
391 | aver = length/(2.*r); |
392 | r -= 1.; |
393 | } |
394 | } |
395 | } |
396 | |
397 | fbData->SetArea(area); |
398 | fbData->SetPerimeter(length); |
399 | fbData->SetRatio(r); |
400 | fbData->SetWidth(aver); |
401 | |
402 | return Standard_True; |
403 | } |