1 // Copyright (C) 2007-2024 CEA, EDF, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #include <GEOMImpl_WrappingDriver.hxx>
25 #include <GEOMAlgo_Splitter.hxx>
26 #include <GEOMUtils.hxx>
28 #include <GEOMImpl_ShapeDriver.hxx>
29 #include <GEOMImpl_IWrap.hxx>
30 #include <GEOMImpl_Types.hxx>
31 #include <GEOMImpl_Block6Explorer.hxx>
32 #include <GEOM_Object.hxx>
34 #include <BRep_Tool.hxx>
35 #include <BRepBuilderAPI_MakeFace.hxx>
36 #include <BRepPrimAPI_MakeSphere.hxx>
37 #if OCC_VERSION_LARGE < 0x07070000
38 #include <BRepAdaptor_HSurface.hxx>
40 #include <BRepAdaptor_Surface.hxx>
43 #include <Geom_Curve.hxx>
44 #include <Geom_Surface.hxx>
45 #include <Geom_Plane.hxx>
46 #include <Geom_BSplineSurface.hxx>
47 #include <GeomPlate_Surface.hxx>
48 #include <GeomPlate_BuildPlateSurface.hxx>
49 #include <GeomPlate_PointConstraint.hxx>
50 #include <GeomPlate_MakeApprox.hxx>
51 #include <GeomPlate_BuildAveragePlane.hxx>
54 #include <gp_Sphere.hxx>
55 #include <TopExp_Explorer.hxx>
57 #include <TopoDS_Shape.hxx>
58 #include <TopoDS_Wire.hxx>
59 #include <TopoDS_Vertex.hxx>
60 #include <TColgp_HArray1OfPnt.hxx>
61 #include <TColStd_HSequenceOfTransient.hxx>
62 #include <ShapeFix_Face.hxx>
64 #include <Standard_NullObject.hxx>
69 #include <Eigen/Dense>
71 //=======================================================================
74 //=======================================================================
75 const Standard_GUID &GEOMImpl_WrappingDriver::GetID()
77 static Standard_GUID aWrapDriver("FF1BBB71-729D-4E83-8232-78E74FC5637C");
81 //=======================================================================
82 // function : GEOMImpl_WrappingDriver
84 //=======================================================================
85 GEOMImpl_WrappingDriver::GEOMImpl_WrappingDriver()
89 //=======================================================================
90 // function : createPointsOnEdges
91 // purpose : create points on edges
92 //=======================================================================
93 static void createPointsOnEdges(const Handle(TColStd_HSequenceOfTransient) & theEdgesFuncs,
94 std::vector<gp_Pnt> &thePoints)
96 for (int i = 1; i <= theEdgesFuncs->Length(); i++)
98 Handle(GEOM_Function) aRefShape = Handle(GEOM_Function)::DownCast(theEdgesFuncs->Value(i));
99 TopoDS_Shape aShape_i = aRefShape->GetValue();
100 if (aShape_i.IsNull())
102 Standard_NullObject::Raise("Edge for face construction is null");
104 TopExp_Explorer exp(aShape_i, TopAbs_EDGE);
105 for (; exp.More(); exp.Next())
107 Standard_Real aFP, aLP, aP;
108 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(TopoDS::Edge(exp.Current()), aFP, aLP);
109 if (!aCurve.IsNull())
111 for (int aPar = 1; aPar <= 9; aPar++)
113 aP = aFP + (aLP - aFP) * (aPar * 0.1);
114 gp_Pnt aPnt = aCurve->Value(aP);
115 thePoints.push_back(aPnt);
122 //================================================================================
123 // function : maxDistanceToFace
124 // purpose : finds max distanse between points and a face
125 //================================================================================
126 static Standard_Real maxDistanceToFace(const std::vector<gp_Pnt>& thePoints,
127 const TopoDS_Face& theFace,
128 const Standard_Real theTolerance)
131 Standard_Real aMaxDist = 0.;
132 for(auto& aPnt : thePoints)
134 gp_Pnt aProj = GEOMUtils::ProjectPointOnFace(aPnt, theFace,U,V,theTolerance);
135 Standard_Real aDist = aProj.Distance(aPnt);
144 //================================================================================
145 // function : divideSphericalShape
146 // purpose : divide spherical shape into two piece
147 // and choose that part that has the points
148 //================================================================================
149 static void divideSphericalShape(TopoDS_Shape &theShape,
150 const TopoDS_Wire &theWire,
151 const std::vector<gp_Pnt> &thePoints,
152 const Standard_Real theTolerance)
154 TopExp_Explorer anExp(theShape, TopAbs_FACE);
155 const TopoDS_Face& aFace = TopoDS::Face(anExp.Current());
156 TopoDS_Face aToolFace;
157 GEOMImpl_Block6Explorer::MakeFace(theWire, false, aToolFace);
158 if(!aToolFace.IsNull())
160 //split sphere and choose right part
161 GEOMAlgo_Splitter PS;
162 PS.AddArgument(aFace);
163 PS.AddTool(aToolFace);
164 PS.SetLimit(TopAbs_FACE);
166 TopoDS_Shape aResultShape = PS.Shape();
167 if(!aResultShape.IsNull())
169 anExp.Init(aResultShape, TopAbs_FACE);
170 for (; anExp.More(); anExp.Next())
172 Standard_Real aDist = maxDistanceToFace(thePoints, TopoDS::Face(anExp.Current()), theTolerance);
173 if(aDist < theTolerance)
175 theShape = TopoDS::Face(anExp.Current());
183 //================================================================================
184 // function : makeFaceFromPointsAndWire
185 // purpose : Create face from set of points with the same approach as for
186 // geompy.makeSmoothingSurface. Cut resulting surface with a wire
187 //================================================================================
188 static TopoDS_Shape makeFaceFromPointsAndWire(const TopoDS_Wire &theWire,
189 const std::vector<gp_Pnt> &theAllPoints)
191 int nbPoints = theAllPoints.size();
192 Handle(TColgp_HArray1OfPnt) anArrayofPnt = new TColgp_HArray1OfPnt(1, nbPoints);
193 for (int i = 0; i < nbPoints; i++) {
194 gp_Pnt aP = theAllPoints[i];
195 anArrayofPnt->SetValue(i+1, aP);
198 // Try to build smoothing surface
199 GeomPlate_BuildAveragePlane gpbap(anArrayofPnt,anArrayofPnt->Length(),Precision::Confusion(),1,1);
200 Handle(Geom_Plane) plane(gpbap.Plane());
202 Standard_Real Umin, Umax, Vmin, Vmax;
203 gpbap.MinMaxBox(Umin,Umax,Vmin,Vmax);
205 TopoDS_Face aInitShape;
206 BRepBuilderAPI_MakeFace mf(plane,Umin,Umax,Vmin,Vmax,Precision::Confusion());
207 aInitShape = mf.Face();
209 GeomPlate_BuildPlateSurface aBuilder(3,10);
210 // ** Initialization of surface
211 #if OCC_VERSION_LARGE < 0x07070000
212 Handle(BRepAdaptor_HSurface) HSI = new BRepAdaptor_HSurface();
213 HSI->ChangeSurface().Initialize(aInitShape);
214 aBuilder.LoadInitSurface( BRep_Tool::Surface(HSI->ChangeSurface().Face()));
216 Handle(BRepAdaptor_Surface) HSI = new BRepAdaptor_Surface();
217 HSI->Initialize(aInitShape);
218 aBuilder.LoadInitSurface( BRep_Tool::Surface(HSI->Face()) );
221 Standard_Integer j, j1, j2;
222 j1 = anArrayofPnt->Lower();
223 j2 = anArrayofPnt->Upper();
224 for (j=j1; j<=j2 ; j++)
226 gp_Pnt aPnt = anArrayofPnt->Value(j);
227 Handle(GeomPlate_PointConstraint) PCont = new GeomPlate_PointConstraint(aPnt,0);
231 Handle(GeomPlate_Surface) gpPlate = aBuilder.Surface();
234 Standard_ConstructionError::Raise("Not possible to build a face with given input, GeomPlate_Surface failed");
237 Standard_Real seuil = Max(0.0001,10*aBuilder.G0Error());
238 GeomPlate_MakeApprox Mapp(gpPlate,0.0001,2,8,seuil);
239 Handle(Geom_Surface) aSurf(Mapp.Surface());
241 //cut surface with a face
243 BRepBuilderAPI_MakeFace aMkFace(aSurf, theWire);
244 if (aMkFace.IsDone())
246 aShape = aMkFace.Shape();
249 TopoDS_Face aFace = TopoDS::Face(aShape);
250 Handle(ShapeFix_Face) aFix = new ShapeFix_Face(aFace);
252 aFix->FixOrientation();
253 aFace = aFix->Face();
258 //=======================================================================
259 // function : Execute
261 //=======================================================================
262 Standard_Integer GEOMImpl_WrappingDriver::Execute(Handle(TFunction_Logbook) & log) const
264 if (Label().IsNull())
266 Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label());
268 GEOMImpl_IWrap aCI(aFunction);
269 Standard_Integer aType = aFunction->GetType();
273 if (aType == WRAPPING_FACE)
275 Handle(TColStd_HSequenceOfTransient) anEdges = aCI.GetEdges();
276 Handle(TColStd_HSequenceOfTransient) aVertices = aCI.GetVertices();
278 int nbEdge = anEdges->Length();
279 int nbVertices = aVertices->Length();
281 if (nbEdge < 1 || nbVertices < 1)
283 Standard_ConstructionError::Raise("No edges or vertices given");
286 Standard_Real aTolerance = aCI.GetTolerance();
287 if (aTolerance < Precision::Confusion())
288 aTolerance = Precision::Confusion();
290 std::vector<gp_Pnt> anAllPoints, aPoints;
291 createPointsOnEdges(anEdges, anAllPoints);
292 for (int i = 1; i <= aVertices->Length(); i++)
294 Handle(GEOM_Function) aRefShape = Handle(GEOM_Function)::DownCast(aVertices->Value(i));
295 TopoDS_Shape aShape_i = aRefShape->GetValue();
296 if (aShape_i.IsNull())
298 Standard_NullObject::Raise("Vertex for face construction is null");
300 TopExp_Explorer exp (aShape_i, TopAbs_VERTEX);
301 for (; exp.More(); exp.Next())
303 gp_Pnt aP = BRep_Tool::Pnt(TopoDS::Vertex(exp.Current()));
304 anAllPoints.push_back(aP);
305 aPoints.push_back(aP);
309 if(anAllPoints.size() == 0)
311 Standard_NullObject::Raise("Shape creation imposible, no valid objects were given");
314 //create wire from edges
315 TopoDS_Wire aWire = GEOMImpl_ShapeDriver::MakeWireFromEdges(anEdges, aTolerance);
318 Standard_NullObject::Raise("Given edges does not create closed contour");
321 aShape = createWrappedFace(aWire, anAllPoints, aPoints, aTolerance);
327 aFunction->SetValue(aShape);
329 log->SetTouched(Label());
334 //================================================================================
336 * \brief Create wrapped face from vector of points and wire
338 //================================================================================
339 TopoDS_Shape GEOMImpl_WrappingDriver::createWrappedFace(const TopoDS_Wire &theWire,
340 const std::vector<gp_Pnt> &theAllPoints,
341 const std::vector<gp_Pnt> &thePoints,
342 const Standard_Real theTolerance) const
346 gp_Pnt aCenter(0,0,0);
347 Standard_Real aRadius = 100;
348 if(isSphere(theAllPoints, aCenter, aRadius, theTolerance))
350 aShape = BRepPrimAPI_MakeSphere(aCenter, aRadius).Shape();
351 divideSphericalShape(aShape, theWire, thePoints, theTolerance);
355 aShape = makeFaceFromPointsAndWire(theWire, theAllPoints);
359 //================================================================================
361 * \brief Returns a name of creation operation and names and values of creation parameters
363 //================================================================================
364 Standard_Boolean GEOMImpl_WrappingDriver::isSphere(const std::vector<gp_Pnt>& thePoints,
366 Standard_Real& theRadius,
367 const Standard_Real theTolerance)const
369 int aNumPoints = thePoints.size();
375 // Create coefficient matrix A and right-hand side vector f
376 Eigen::MatrixXd A(aNumPoints, 4);
377 Eigen::VectorXd f(aNumPoints);
383 for (int i = 0; i < aNumPoints; ++i)
385 X = thePoints[i].X();
386 Y = thePoints[i].Y();
387 Z = thePoints[i].Z();
392 f(i) = X * X + Y * Y + Z * Z;
395 // Solve linear equations to get coefficients
396 Eigen::VectorXd c = A.colPivHouseholderQr().solve(f);
398 Standard_Real t = c[0] * c[0] + c[1] * c[1] + c[2] * c[2] + c[3];
399 theRadius = std::sqrt(t);
400 theCenter.SetCoord(c[0], c[1], c[2]);
402 //check that all points belong to the sphere within theTolerance
403 std::vector<Standard_Real> aDists;
404 for(const auto& aPnt : thePoints)
406 aDists.push_back(aPnt.Distance(theCenter));
410 Standard_Real sumDistances = std::accumulate(aDists.begin(), aDists.end(), 0.0);
411 Standard_Real averageDistance = sumDistances / aDists.size();
413 if (std::fabs(averageDistance - theRadius) > theTolerance) {
421 //================================================================================
423 * \brief Returns a name of creation operation and names and values of creation parameters
425 //================================================================================
427 bool GEOMImpl_WrappingDriver::
428 GetCreationInformation(std::string &theOperationName,
429 std::vector<GEOM_Param> &theParams)
431 if (Label().IsNull()) return 0;
432 Handle(GEOM_Function) function = GEOM_Function::GetFunction(Label());
434 GEOMImpl_IWrap aCI( function );
435 Standard_Integer aType = function->GetType();
437 theOperationName = "WRAPPEDFACE";
441 AddParam(theParams, "Edges", aCI.GetEdges());
442 AddParam(theParams, "Vertices", aCI.GetVertices());
443 AddParam(theParams, "Tolerance", aCI.GetTolerance());
452 IMPLEMENT_STANDARD_RTTIEXT(GEOMImpl_WrappingDriver, GEOM_BaseDriver)