FreeCAD
253 строки · 8.7 Кб
1/***************************************************************************
2* Copyright (c) 2015 Werner Mayer <wmayer[at]users.sourceforge.net> *
3* *
4* This file is part of the FreeCAD CAx development system. *
5* *
6* This library is free software; you can redistribute it and/or *
7* modify it under the terms of the GNU Library General Public *
8* License as published by the Free Software Foundation; either *
9* version 2 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 *
14* GNU Library General Public License for more details. *
15* *
16* You should have received a copy of the GNU Library General Public *
17* License along with this library; see the file COPYING.LIB. If not, *
18* write to the Free Software Foundation, Inc., 59 Temple Place, *
19* Suite 330, Boston, MA 02111-1307, USA *
20* *
21***************************************************************************/
22
23#include "PreCompiled.h"
24#if defined(HAVE_PCL_OPENNURBS)
25#ifndef _PreComp_
26#include <map>
27
28#include <Geom_BSplineSurface.hxx>
29#include <TColStd_Array1OfInteger.hxx>
30#include <TColStd_Array1OfReal.hxx>
31#include <TColStd_Array2OfReal.hxx>
32#include <TColgp_Array2OfPnt.hxx>
33#endif
34
35#include <Mod/Points/App/PointsPy.h>
36
37#include "BSplineFitting.h"
38
39#include <pcl/pcl_config.h>
40#if PCL_VERSION_COMPARE(>=, 1, 7, 0)
41#include <pcl/io/pcd_io.h>
42#include <pcl/point_cloud.h>
43#include <pcl/point_types.h>
44#include <pcl/surface/on_nurbs/fitting_curve_2d_asdm.h>
45#include <pcl/surface/on_nurbs/fitting_surface_tdm.h>
46#endif
47
48using namespace Reen;
49
50
51BSplineFitting::BSplineFitting(const std::vector<Base::Vector3f>& pts)
52: myPoints(pts)
53, myIterations(10)
54, myOrder(3)
55, myRefinement(4)
56, myInteriorSmoothness(0.2)
57, myInteriorWeight(1.0)
58, myBoundarySmoothness(0.2)
59, myBoundaryWeight(0.0)
60{}
61
62void BSplineFitting::setIterations(unsigned value)
63{
64myIterations = value;
65}
66
67void BSplineFitting::setOrder(unsigned value)
68{
69myOrder = value;
70}
71
72void BSplineFitting::setRefinement(unsigned value)
73{
74myRefinement = value;
75}
76
77void BSplineFitting::setInteriorSmoothness(double value)
78{
79myInteriorSmoothness = value;
80}
81
82void BSplineFitting::setInteriorWeight(double value)
83{
84myInteriorWeight = value;
85}
86
87void BSplineFitting::setBoundarySmoothness(double value)
88{
89myBoundarySmoothness = value;
90}
91
92void BSplineFitting::setBoundaryWeight(double value)
93{
94myBoundaryWeight = value;
95}
96
97Handle(Geom_BSplineSurface) BSplineFitting::perform()
98{
99#if PCL_VERSION_COMPARE(>=, 1, 7, 0)
100pcl::on_nurbs::NurbsDataSurface data;
101for (std::vector<Base::Vector3f>::const_iterator it = myPoints.begin(); it != myPoints.end();
102++it) {
103if (!pcl_isnan(it->x) && !pcl_isnan(it->y) && !pcl_isnan(it->z)) {
104data.interior.push_back(Eigen::Vector3d(it->x, it->y, it->z));
105}
106}
107
108
109// fit B-spline surface
110//
111
112pcl::on_nurbs::FittingSurface::Parameter params;
113params.interior_smoothness = myInteriorSmoothness;
114params.interior_weight = myInteriorWeight;
115params.boundary_smoothness = myBoundarySmoothness;
116params.boundary_weight = myBoundaryWeight;
117
118// initialize
119ON_NurbsSurface nurbs = pcl::on_nurbs::FittingSurface::initNurbsPCABoundingBox(myOrder, &data);
120pcl::on_nurbs::FittingSurface fit(&data, nurbs);
121// fit.setQuiet (false); // enable/disable debug output
122
123// surface refinement
124for (unsigned i = 0; i < myRefinement; i++) {
125fit.refine(0);
126fit.refine(1);
127fit.assemble(params);
128fit.solve();
129}
130
131// surface fitting with final refinement level
132for (unsigned i = 0; i < myIterations; i++) {
133fit.assemble(params);
134fit.solve();
135}
136
137// fit B-spline curve
138#if 0
139// parameters
140pcl::on_nurbs::FittingCurve2dAPDM::FitParameter curve_params;
141curve_params.addCPsAccuracy = 5e-2;
142curve_params.addCPsIteration = 3;
143curve_params.maxCPs = 200;
144curve_params.accuracy = 1e-3;
145curve_params.iterations = 100;
146
147curve_params.param.closest_point_resolution = 0;
148curve_params.param.closest_point_weight = 1.0;
149curve_params.param.closest_point_sigma2 = 0.1;
150curve_params.param.interior_sigma2 = 0.00001;
151curve_params.param.smooth_concavity = 1.0;
152curve_params.param.smoothness = 1.0;
153
154// initialisation (circular)
155pcl::on_nurbs::NurbsDataCurve2d curve_data;
156curve_data.interior = data.interior_param;
157curve_data.interior_weight_function.push_back(true);
158ON_NurbsCurve curve_nurbs = pcl::on_nurbs::FittingCurve2dAPDM::initNurbsCurve2D(order, curve_data.interior);
159
160// curve fitting
161pcl::on_nurbs::FittingCurve2dASDM curve_fit (&curve_data, curve_nurbs);
162// curve_fit.setQuiet (false); // enable/disable debug output
163curve_fit.fitting (curve_params);
164#endif
165
166// u parameters
167int numUKnots = fit.m_nurbs.KnotCount(0);
168int numUPoles = fit.m_nurbs.CVCount(0);
169int uDegree = fit.m_nurbs.Degree(0);
170bool uPeriodic = fit.m_nurbs.IsPeriodic(0) ? true : false;
171std::map<Standard_Real, int> uKnots;
172
173// v parameters
174int numVKnots = fit.m_nurbs.KnotCount(1);
175int numVPoles = fit.m_nurbs.CVCount(1);
176int vDegree = fit.m_nurbs.Degree(1);
177bool vPeriodic = fit.m_nurbs.IsPeriodic(1) ? true : false;
178std::map<Standard_Real, int> vKnots;
179
180TColgp_Array2OfPnt poles(1, numUPoles, 1, numVPoles);
181TColStd_Array2OfReal weights(1, numUPoles, 1, numVPoles);
182
183for (int i = 0; i < numUPoles; i++) {
184for (int j = 0; j < numVPoles; j++) {
185ON_3dPoint cv;
186fit.m_nurbs.GetCV(i, j, cv);
187poles.SetValue(i + 1, j + 1, gp_Pnt(cv.x, cv.y, cv.z));
188
189Standard_Real weight = fit.m_nurbs.Weight(i, j);
190weights.SetValue(i + 1, j + 1, weight);
191}
192}
193
194uKnots[fit.m_nurbs.SuperfluousKnot(0, 0)] = 1;
195uKnots[fit.m_nurbs.SuperfluousKnot(0, 1)] = 1;
196for (int i = 0; i < numUKnots; i++) {
197Standard_Real value = fit.m_nurbs.Knot(0, i);
198std::map<Standard_Real, int>::iterator it = uKnots.find(value);
199if (it == uKnots.end()) {
200uKnots[value] = 1;
201}
202else {
203it->second++;
204}
205}
206
207vKnots[fit.m_nurbs.SuperfluousKnot(1, 0)] = 1;
208vKnots[fit.m_nurbs.SuperfluousKnot(1, 1)] = 1;
209for (int i = 0; i < numVKnots; i++) {
210Standard_Real value = fit.m_nurbs.Knot(1, i);
211std::map<Standard_Real, int>::iterator it = vKnots.find(value);
212if (it == vKnots.end()) {
213vKnots[value] = 1;
214}
215else {
216it->second++;
217}
218}
219
220TColStd_Array1OfReal uKnotArray(1, uKnots.size());
221TColStd_Array1OfInteger uMultArray(1, uKnots.size());
222int index = 1;
223for (std::map<Standard_Real, int>::iterator it = uKnots.begin(); it != uKnots.end();
224++it, index++) {
225uKnotArray.SetValue(index, it->first);
226uMultArray.SetValue(index, it->second);
227}
228
229TColStd_Array1OfReal vKnotArray(1, vKnots.size());
230TColStd_Array1OfInteger vMultArray(1, vKnots.size());
231index = 1;
232for (std::map<Standard_Real, int>::iterator it = vKnots.begin(); it != vKnots.end();
233++it, index++) {
234vKnotArray.SetValue(index, it->first);
235vMultArray.SetValue(index, it->second);
236}
237
238Handle(Geom_BSplineSurface) spline = new Geom_BSplineSurface(poles,
239weights,
240uKnotArray,
241vKnotArray,
242uMultArray,
243vMultArray,
244uDegree,
245vDegree,
246uPeriodic,
247vPeriodic);
248return spline;
249#else
250return Handle(Geom_BSplineSurface)();
251#endif
252}
253#endif // HAVE_PCL_OPENNURBS
254