Salome HOME
Fix for the issue #2753 : error when dump/load script
[modules/shaper.git] / src / ConstructionPlugin / ConstructionPlugin_Plane.cpp
1 // Copyright (C) 2014-2017  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
19 //
20
21 #include "ConstructionPlugin_Plane.h"
22
23 #include <Config_PropManager.h>
24
25 #include <GeomAlgoAPI_FaceBuilder.h>
26 #include <GeomAlgoAPI_Rotation.h>
27 #include <GeomAlgoAPI_ShapeTools.h>
28
29 #include <GeomAPI_Ax1.h>
30 #include <GeomAPI_Edge.h>
31 #include <GeomAPI_Face.h>
32 #include <GeomAPI_Lin.h>
33 #include <GeomAPI_Pln.h>
34 #include <GeomAPI_Pnt.h>
35 #include <GeomAPI_Pnt2d.h>
36 #include <GeomAPI_ShapeIterator.h>
37 #include <GeomAPI_Vertex.h>
38 #include <GeomAPI_XYZ.h>
39
40 #include <ModelAPI_AttributeDouble.h>
41 #include <ModelAPI_AttributeIntArray.h>
42 #include <ModelAPI_AttributeSelection.h>
43 #include <ModelAPI_AttributeString.h>
44 #include <ModelAPI_AttributeBoolean.h>
45 #include <ModelAPI_ResultConstruction.h>
46 #include <ModelAPI_Session.h>
47 #include <ModelAPI_Validator.h>
48
49
50 static GeomShapePtr faceByThreeVertices(const std::shared_ptr<GeomAPI_Vertex> theV1,
51                                         const std::shared_ptr<GeomAPI_Vertex> theV2,
52                                         const std::shared_ptr<GeomAPI_Vertex> theV3);
53 static std::shared_ptr<GeomAPI_Face> makeRectangularFace(
54   const std::shared_ptr<GeomAPI_Face> theFace,
55   const std::shared_ptr<GeomAPI_Pln> thePln);
56
57 //==================================================================================================
58 ConstructionPlugin_Plane::ConstructionPlugin_Plane()
59 {
60 }
61
62 //==================================================================================================
63 void ConstructionPlugin_Plane::initAttributes()
64 {
65   data()->addAttribute(ConstructionPlugin_Plane::CREATION_METHOD(),
66                        ModelAPI_AttributeString::typeId());
67
68   data()->addAttribute(PLANE(), ModelAPI_AttributeSelection::typeId());
69   data()->addAttribute(DISTANCE(), ModelAPI_AttributeDouble::typeId());
70   // By general equation.
71   data()->addAttribute(A(), ModelAPI_AttributeDouble::typeId());
72   data()->addAttribute(B(), ModelAPI_AttributeDouble::typeId());
73   data()->addAttribute(C(), ModelAPI_AttributeDouble::typeId());
74   data()->addAttribute(D(), ModelAPI_AttributeDouble::typeId());
75   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), A());
76   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), B());
77   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), C());
78   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), D());
79
80   // By three points.
81   data()->addAttribute(POINT1(), ModelAPI_AttributeSelection::typeId());
82   data()->addAttribute(POINT2(), ModelAPI_AttributeSelection::typeId());
83   data()->addAttribute(POINT3(), ModelAPI_AttributeSelection::typeId());
84
85   // By line and point.
86   data()->addAttribute(LINE(), ModelAPI_AttributeSelection::typeId());
87   data()->addAttribute(POINT(), ModelAPI_AttributeSelection::typeId());
88   data()->addAttribute(PERPENDICULAR(), ModelAPI_AttributeBoolean::typeId());
89
90   // By other plane.
91   data()->addAttribute(CREATION_METHOD_BY_OTHER_PLANE_OPTION(), ModelAPI_AttributeString::typeId());
92   data()->addAttribute(REVERSE(), ModelAPI_AttributeBoolean::typeId());
93   data()->addAttribute(COINCIDENT_POINT(), ModelAPI_AttributeSelection::typeId());
94   data()->addAttribute(AXIS(), ModelAPI_AttributeSelection::typeId());
95   data()->addAttribute(ANGLE(), ModelAPI_AttributeDouble::typeId());
96
97   // By two parallel planes.
98   data()->addAttribute(PLANE1(), ModelAPI_AttributeSelection::typeId());
99   data()->addAttribute(PLANE2(), ModelAPI_AttributeSelection::typeId());
100 }
101
102 //==================================================================================================
103 void ConstructionPlugin_Plane::execute()
104 {
105   GeomShapePtr aShape;
106
107   std::string aCreationMethod = string(CREATION_METHOD())->value();
108   if(aCreationMethod == CREATION_METHOD_BY_GENERAL_EQUATION() ||
109       aCreationMethod == "PlaneByGeneralEquation") {
110     aShape = createByGeneralEquation();
111   } else if(aCreationMethod == CREATION_METHOD_BY_THREE_POINTS()) {
112     aShape = createByThreePoints();
113   } else if(aCreationMethod == CREATION_METHOD_BY_LINE_AND_POINT()) {
114     aShape = createByLineAndPoint();
115   } else if(aCreationMethod == CREATION_METHOD_BY_OTHER_PLANE()) {
116     std::string aCreationMethodOption = string(CREATION_METHOD_BY_OTHER_PLANE_OPTION())->value();
117     if(aCreationMethodOption == CREATION_METHOD_BY_DISTANCE_FROM_OTHER()) {
118       aShape = createByDistanceFromOther();
119     } else if(aCreationMethodOption == CREATION_METHOD_BY_COINCIDENT_TO_POINT()) {
120       aShape = createByCoincidentPoint();
121     } else if(aCreationMethodOption == CREATION_METHOD_BY_ROTATION()) {
122       aShape = createByRotation();
123     }
124   } else if(aCreationMethod == CREATION_METHOD_BY_TWO_PARALLEL_PLANES()) {
125     aShape = createByTwoParallelPlanes();
126   } else {
127     setError("Error: Plane creation method \"" + aCreationMethod + "\" not supported.");
128     return;
129   }
130
131   if(!aShape.get()) {
132     setError("Error: Could not create a plane.");
133     return;
134   }
135
136   ResultConstructionPtr aConstr = document()->createConstruction(data());
137   aConstr->setInfinite(true);
138   aConstr->setShape(aShape);
139   setResult(aConstr);
140 }
141
142 //==================================================================================================
143 bool ConstructionPlugin_Plane::customisePresentation(ResultPtr theResult, AISObjectPtr thePrs,
144                                                 std::shared_ptr<GeomAPI_ICustomPrs> theDefaultPrs)
145 {
146   std::vector<int> aColor;
147   // get color from the attribute of the result
148   if (theResult.get() != NULL &&
149       theResult->data()->attribute(ModelAPI_Result::COLOR_ID()).get() != NULL) {
150     AttributeIntArrayPtr aColorAttr = theResult->data()->intArray(ModelAPI_Result::COLOR_ID());
151     if (aColorAttr.get() && aColorAttr->size()) {
152       aColor.push_back(aColorAttr->value(0));
153       aColor.push_back(aColorAttr->value(1));
154       aColor.push_back(aColorAttr->value(2));
155     }
156   }
157   if (aColor.empty())
158     aColor = Config_PropManager::color("Visualization", "construction_plane_color");
159
160   bool isCustomized = false;
161   if (aColor.size() == 3)
162     isCustomized = thePrs->setColor(aColor[0], aColor[1], aColor[2]);
163
164   isCustomized = thePrs->setTransparensy(0.6) || isCustomized;
165
166   return isCustomized;
167 }
168
169 //==================================================================================================
170 std::shared_ptr<GeomAPI_Shape> ConstructionPlugin_Plane::createByGeneralEquation()
171 {
172   AttributeDoublePtr anAttrA = real(ConstructionPlugin_Plane::A());
173   AttributeDoublePtr anAttrB = real(ConstructionPlugin_Plane::B());
174   AttributeDoublePtr anAttrC = real(ConstructionPlugin_Plane::C());
175   AttributeDoublePtr anAttrD = real(ConstructionPlugin_Plane::D());
176   std::shared_ptr<GeomAPI_Shape> aPlaneFace;
177   if ((anAttrA.get() != NULL) && (anAttrB.get() != NULL) &&
178       (anAttrC.get() != NULL) && (anAttrD.get() != NULL) &&
179       anAttrA->isInitialized() && anAttrB->isInitialized() &&
180       anAttrC->isInitialized() && anAttrD->isInitialized() ) {
181     double aA = anAttrA->value(), aB = anAttrB->value(),
182            aC = anAttrC->value(), aD = anAttrD->value();
183     std::shared_ptr<GeomAPI_Pln> aPlane =
184       std::shared_ptr<GeomAPI_Pln>(new GeomAPI_Pln(aA, aB, aC, aD));
185     double aSize = Config_PropManager::real(SKETCH_TAB_NAME, "planes_size");
186     if (aSize <= 1.e-7)
187       aSize = 200;  // Set default value
188     aSize *= 4.;
189     aPlaneFace = GeomAlgoAPI_FaceBuilder::squareFace(aPlane, aSize);
190   }
191   return aPlaneFace;
192 }
193
194 //==================================================================================================
195 std::shared_ptr<GeomAPI_Shape> ConstructionPlugin_Plane::createByThreePoints()
196 {
197   // Get first point.
198   AttributeSelectionPtr aPointSelection1 = selection(POINT1());
199   GeomShapePtr aPointShape1 = aPointSelection1->value();
200   if(!aPointShape1.get()) {
201     aPointShape1 = aPointSelection1->context()->shape();
202   }
203   std::shared_ptr<GeomAPI_Vertex> aVertex1(new GeomAPI_Vertex(aPointShape1));
204
205   // Get second point.
206   AttributeSelectionPtr aPointSelection2 = selection(POINT2());
207   GeomShapePtr aPointShape2 = aPointSelection2->value();
208   if(!aPointShape2.get()) {
209     aPointShape2 = aPointSelection2->context()->shape();
210   }
211   std::shared_ptr<GeomAPI_Vertex> aVertex2(new GeomAPI_Vertex(aPointShape2));
212
213   // Get third point.
214   AttributeSelectionPtr aPointSelection3 = selection(POINT3());
215   GeomShapePtr aPointShape3 = aPointSelection3->value();
216   if(!aPointShape3.get()) {
217     aPointShape3 = aPointSelection3->context()->shape();
218   }
219   std::shared_ptr<GeomAPI_Vertex> aVertex3(new GeomAPI_Vertex(aPointShape3));
220
221   GeomShapePtr aRes = faceByThreeVertices(aVertex1, aVertex2, aVertex3);
222
223   return aRes;
224 }
225
226 //==================================================================================================
227 std::shared_ptr<GeomAPI_Shape> ConstructionPlugin_Plane::createByLineAndPoint()
228 {
229   // Get edge.
230   AttributeSelectionPtr anEdgeSelection = selection(LINE());
231   GeomShapePtr aLineShape = anEdgeSelection->value();
232   if(!aLineShape.get()) {
233     aLineShape = anEdgeSelection->context()->shape();
234   }
235   std::shared_ptr<GeomAPI_Edge> anEdge;
236   if (aLineShape->isEdge()) {
237     anEdge = aLineShape->edge();
238   }
239   else if (aLineShape->isCompound()) {
240     GeomAPI_ShapeIterator anIt(aLineShape);
241     anEdge = anIt.current()->edge();
242   }
243
244   // Get point.
245   AttributeSelectionPtr aPointSelection = selection(POINT());
246   GeomShapePtr aPointShape = aPointSelection->value();
247   if(!aPointShape.get()) {
248     aPointShape = aPointSelection->context()->shape();
249   }
250   std::shared_ptr<GeomAPI_Vertex> aVertex(new GeomAPI_Vertex(aPointShape));
251
252   // Get perpendicular flag.
253   bool anIsPerpendicular= boolean(PERPENDICULAR())->value();
254
255   GeomShapePtr aRes;
256   if(anIsPerpendicular) {
257     std::shared_ptr<GeomAPI_Lin> aLin = anEdge->line();
258     std::shared_ptr<GeomAPI_Pnt> aPnt = aVertex->point();
259     std::shared_ptr<GeomAPI_Pln> aNewPln(new GeomAPI_Pln(aPnt, aLin->direction()));
260     double aSize = aLin->distance(aPnt) * 2;
261     // point may belong to line, so for the face size use maximum distance between point and line
262     // and the line size (distance between the start and end point)
263     double aDistance = anEdge->firstPoint()->distance(anEdge->lastPoint());
264     aRes = GeomAlgoAPI_FaceBuilder::squareFace(aNewPln, aSize > aDistance ? aSize : aDistance);
265   } else {
266     std::shared_ptr<GeomAPI_Vertex> aV1, aV2;
267     GeomAlgoAPI_ShapeTools::findBounds(anEdge, aV1, aV2);
268     aRes = faceByThreeVertices(aV1, aV2, aVertex);
269   }
270
271   return aRes;
272 }
273
274 //==================================================================================================
275 std::shared_ptr<GeomAPI_Shape> ConstructionPlugin_Plane::createByDistanceFromOther()
276 {
277   AttributeSelectionPtr aFaceAttr = data()->selection(ConstructionPlugin_Plane::PLANE());
278   AttributeDoublePtr aDistAttr = data()->real(ConstructionPlugin_Plane::DISTANCE());
279   std::shared_ptr<GeomAPI_Shape> aPlane;
280   if ((aFaceAttr.get() != NULL) &&
281       (aDistAttr.get() != NULL) &&
282       aFaceAttr->isInitialized() && aDistAttr->isInitialized()) {
283
284     double aDist = aDistAttr->value();
285     bool anIsReverse = boolean(REVERSE())->value();
286     if(anIsReverse) aDist = -aDist;
287     GeomShapePtr aShape = aFaceAttr->value();
288     if (!aShape.get()) {
289       aShape = aFaceAttr->context()->shape();
290     }
291
292     if(!aShape.get()) {
293       return aPlane;
294     }
295
296     std::shared_ptr<GeomAPI_Face> aFace;
297     if (aShape->isFace()) {
298       aFace = aShape->face();
299     }
300     else if (aShape->isCompound()) {
301       GeomAPI_ShapeIterator anIt(aShape);
302       aFace = anIt.current()->face();
303     }
304
305     std::shared_ptr<GeomAPI_Pln> aPln = aFace->getPlane();
306     std::shared_ptr<GeomAPI_Pnt> aOrig = aPln->location();
307     std::shared_ptr<GeomAPI_Dir> aDir = aPln->direction();
308
309     aOrig->translate(aDir, aDist);
310     std::shared_ptr<GeomAPI_Pln> aNewPln(new GeomAPI_Pln(aOrig, aDir));
311
312     aPlane = makeRectangularFace(aFace, aNewPln);
313   }
314   return aPlane;
315 }
316
317 //==================================================================================================
318 std::shared_ptr<GeomAPI_Shape> ConstructionPlugin_Plane::createByCoincidentPoint()
319 {
320   // Get face.
321   AttributeSelectionPtr aFaceSelection = selection(PLANE());
322   GeomShapePtr aFaceShape = aFaceSelection->value();
323   if(!aFaceShape.get()) {
324     aFaceShape = aFaceSelection->context()->shape();
325   }
326   std::shared_ptr<GeomAPI_Face> aFace;
327   if (aFaceShape->isFace()) {
328     aFace = aFaceShape->face();
329   }
330   else if (aFaceShape->isCompound()) {
331     GeomAPI_ShapeIterator anIt(aFaceShape);
332     aFace = anIt.current()->face();
333   }
334
335   // Get point.
336   AttributeSelectionPtr aPointSelection = selection(COINCIDENT_POINT());
337   GeomShapePtr aPointShape = aPointSelection->value();
338   if(!aPointShape.get()) {
339     aPointShape = aPointSelection->context()->shape();
340   }
341   std::shared_ptr<GeomAPI_Vertex> aVertex(new GeomAPI_Vertex(aPointShape));
342
343   std::shared_ptr<GeomAPI_Pnt> anOrig = aVertex->point();
344   std::shared_ptr<GeomAPI_Pln> aPln = aFace->getPlane();
345   std::shared_ptr<GeomAPI_Dir> aDir = aPln->direction();
346
347   std::shared_ptr<GeomAPI_Pln> aNewPln(new GeomAPI_Pln(anOrig, aDir));
348
349   return makeRectangularFace(aFace, aNewPln);
350 }
351
352 //==================================================================================================
353 std::shared_ptr<GeomAPI_Shape> ConstructionPlugin_Plane::createByRotation()
354 {
355   // Get face.
356   AttributeSelectionPtr aFaceSelection = selection(PLANE());
357   GeomShapePtr aFaceShape = aFaceSelection->value();
358   if(!aFaceShape.get()) {
359     aFaceShape = aFaceSelection->context()->shape();
360   }
361   std::shared_ptr<GeomAPI_Face> aFace;
362   if (aFaceShape->isFace()) {
363     aFace = aFaceShape->face();
364   }
365   else if (aFaceShape->isCompound()) {
366     GeomAPI_ShapeIterator anIt(aFaceShape);
367     aFace = anIt.current()->face();
368   }
369   aFace = makeRectangularFace(aFace, aFace->getPlane());
370
371   // Get axis.
372   AttributeSelectionPtr anAxisSelection = selection(AXIS());
373   GeomShapePtr anAxisShape = anAxisSelection->value();
374   if(!anAxisShape.get()) {
375     anAxisShape = anAxisSelection->context()->shape();
376   }
377   std::shared_ptr<GeomAPI_Edge> anEdge;
378   if (anAxisShape->isEdge()) {
379     anEdge = anAxisShape->edge();
380   }
381   else if (anAxisShape->isCompound()) {
382     GeomAPI_ShapeIterator anIt(anAxisShape);
383     anEdge = anIt.current()->edge();
384   }
385
386   std::shared_ptr<GeomAPI_Ax1> anAxis =
387     std::shared_ptr<GeomAPI_Ax1>(new GeomAPI_Ax1(anEdge->line()->location(),
388                                                  anEdge->line()->direction()));
389
390   // Getting angle.
391   double anAngle = real(ANGLE())->value();
392
393   GeomAlgoAPI_Rotation aRotationAlgo(aFace, anAxis, anAngle);
394   if (!aRotationAlgo.check()) {
395     setError(aRotationAlgo.getError());
396     return GeomShapePtr();
397   }
398   aRotationAlgo.build();
399   if (!aRotationAlgo.isDone()) {
400     setError("Error: Failed to rotate plane");
401     return GeomShapePtr();
402   }
403
404   std::shared_ptr<GeomAPI_Face> aRes(new GeomAPI_Face(aRotationAlgo.shape()));
405   return aRes;
406 }
407
408 //==================================================================================================
409 std::shared_ptr<GeomAPI_Shape> ConstructionPlugin_Plane::createByTwoParallelPlanes()
410 {
411   // Get plane 1.
412   AttributeSelectionPtr aFaceSelection1 = selection(PLANE1());
413   GeomShapePtr aFaceShape1 = aFaceSelection1->value();
414   if(!aFaceShape1.get()) {
415     aFaceShape1 = aFaceSelection1->context()->shape();
416   }
417   std::shared_ptr<GeomAPI_Face> aFace1;
418   if (aFaceShape1->isFace()) {
419     aFace1 = aFaceShape1->face();
420   }
421   else if (aFaceShape1->isCompound()) {
422     GeomAPI_ShapeIterator anIt(aFaceShape1);
423     aFace1 = anIt.current()->face();
424   }
425   std::shared_ptr<GeomAPI_Pln> aPln1 = aFace1->getPlane();
426
427   // Get plane 2.
428   AttributeSelectionPtr aFaceSelection2 = selection(PLANE2());
429   GeomShapePtr aFaceShape2 = aFaceSelection2->value();
430   if(!aFaceShape2.get()) {
431     aFaceShape2 = aFaceSelection2->context()->shape();
432   }
433   std::shared_ptr<GeomAPI_Face> aFace2;
434   if (aFaceShape2->isFace()) {
435     aFace2 = aFaceShape2->face();
436   }
437   else if (aFaceShape2->isCompound()) {
438     GeomAPI_ShapeIterator anIt(aFaceShape2);
439     aFace2 = anIt.current()->face();
440   }
441   std::shared_ptr<GeomAPI_Pln> aPln2 = aFace2->getPlane();
442
443   std::shared_ptr<GeomAPI_Pnt> anOrig1 = aPln1->location();
444   std::shared_ptr<GeomAPI_Pnt> aPntOnPln2 = aPln2->project(anOrig1);
445
446   std::shared_ptr<GeomAPI_Pnt> aNewOrig(new GeomAPI_Pnt(anOrig1->xyz()->added(
447     aPntOnPln2->xyz())->multiplied(0.5)));
448
449   std::shared_ptr<GeomAPI_Pln> aNewPln(new GeomAPI_Pln(aNewOrig, aPln1->direction()));
450
451   std::shared_ptr<GeomAPI_Face> aRes = makeRectangularFace(aFace1, aNewPln);
452
453   return aRes;
454 }
455
456 //==================================================================================================
457 GeomShapePtr faceByThreeVertices(const std::shared_ptr<GeomAPI_Vertex> theV1,
458                                  const std::shared_ptr<GeomAPI_Vertex> theV2,
459                                  const std::shared_ptr<GeomAPI_Vertex> theV3)
460 {
461   std::shared_ptr<GeomAPI_Face> aFace =
462     GeomAlgoAPI_FaceBuilder::planarFaceByThreeVertices(theV1, theV2, theV3);
463
464   ListOfShape anObjects;
465   anObjects.push_back(theV1);
466   anObjects.push_back(theV2);
467   anObjects.push_back(theV3);
468   std::list<std::shared_ptr<GeomAPI_Pnt> > aBoundingPoints =
469     GeomAlgoAPI_ShapeTools::getBoundingBox(anObjects, 1.0);
470   GeomShapePtr aRes = GeomAlgoAPI_ShapeTools::fitPlaneToBox(aFace, aBoundingPoints);
471
472   return aRes;
473 }
474
475 //==================================================================================================
476 std::shared_ptr<GeomAPI_Face> makeRectangularFace(const std::shared_ptr<GeomAPI_Face> theFace,
477                                                   const std::shared_ptr<GeomAPI_Pln> thePln)
478 {
479   // Create rectangular face close to the selected
480   double aXmin, aYmin, Zmin, aXmax, aYmax, Zmax;
481   theFace->computeSize(aXmin, aYmin, Zmin, aXmax, aYmax, Zmax);
482
483   // use all 8 points of the bounding box to find the 2D bounds
484   bool isFirst = true;
485   double aMinX2d, aMaxX2d, aMinY2d, aMaxY2d;
486   for(int aXIsMin = 0; aXIsMin < 2; aXIsMin++) {
487     for(int aYIsMin = 0; aYIsMin < 2; aYIsMin++) {
488       for(int aZIsMin = 0; aZIsMin < 2; aZIsMin++) {
489         std::shared_ptr<GeomAPI_Pnt> aPnt(new GeomAPI_Pnt(
490           aXIsMin ? aXmin : aXmax, aYIsMin ? aYmin : aYmax, aZIsMin ? Zmin : Zmax));
491         std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aPnt->to2D(thePln);
492         if (isFirst || aPnt2d->x() < aMinX2d)
493           aMinX2d = aPnt2d->x();
494         if (isFirst || aPnt2d->y() < aMinY2d)
495           aMinY2d = aPnt2d->y();
496         if (isFirst || aPnt2d->x() > aMaxX2d)
497           aMaxX2d = aPnt2d->x();
498         if (isFirst || aPnt2d->y() > aMaxY2d)
499           aMaxY2d = aPnt2d->y();
500         if (isFirst)
501           isFirst = !isFirst;
502       }
503     }
504   }
505   double aWgap = (aMaxX2d - aMinX2d) * 0.1;
506   double aHgap = (aMaxY2d - aMinY2d) * 0.1;
507   std::shared_ptr<GeomAPI_Face> aResFace = GeomAlgoAPI_FaceBuilder::planarFace(thePln,
508     aMinX2d - aWgap, aMinY2d - aHgap, aMaxX2d - aMinX2d + 2. * aWgap,
509     aMaxY2d - aMinY2d + 2. * aHgap);
510
511   return aResFace;
512 }