diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ee1122b8..a53048377 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -521,6 +521,10 @@ else(FREECAD_LIBPACK_USE) find_package(Eigen3) +# -------------------------------- pcl ---------------------------------- + + find_package(PCL COMPONENTS common kdtree features surface) + # -------------------------------- ODE ---------------------------------- # find_package(ODE) diff --git a/src/Mod/Points/App/AppPointsPy.cpp b/src/Mod/Points/App/AppPointsPy.cpp index ad280d915..129b2bd4b 100644 --- a/src/Mod/Points/App/AppPointsPy.cpp +++ b/src/Mod/Points/App/AppPointsPy.cpp @@ -24,7 +24,7 @@ #include "PreCompiled.h" #ifndef _PreComp_ #endif - + #include #include #include @@ -168,3 +168,4 @@ struct PyMethodDef Points_Import_methods[] = { {NULL, NULL} /* end of table marker */ }; + diff --git a/src/Mod/ReverseEngineering/App/AppReverseEngineeringPy.cpp b/src/Mod/ReverseEngineering/App/AppReverseEngineeringPy.cpp index 3d2d116d7..7768b2b4a 100644 --- a/src/Mod/ReverseEngineering/App/AppReverseEngineeringPy.cpp +++ b/src/Mod/ReverseEngineering/App/AppReverseEngineeringPy.cpp @@ -22,7 +22,7 @@ #include "PreCompiled.h" -#ifndef _PreComp_ +#ifndef _PreComp_ # include # include #endif @@ -32,8 +32,12 @@ #include #include +#include +#include +#include #include "ApproxSurface.h" +#include "SurfaceTriangulation.h" using namespace Reen; @@ -46,10 +50,10 @@ static PyObject * approxSurface(PyObject *self, PyObject *args) int pointsU=6,pointsV=6; if (!PyArg_ParseTuple(args, "O|iiii",&o,&orderU,&orderV,&pointsU,&pointsV)) return NULL; - + PY_TRY { Py::Sequence l(o); - TColgp_Array1OfPnt clPoints(0, l.size()-1); + TColgp_Array1OfPnt clPoints(0, l.size()-1); int index=0; for (Py::Sequence::iterator it = l.begin(); it != l.end(); ++it) { @@ -59,15 +63,15 @@ static PyObject * approxSurface(PyObject *self, PyObject *args) (double)Py::Float(t.getItem(1)), (double)Py::Float(t.getItem(2))); } - - Reen::BSplineParameterCorrection pc(orderU,orderV,pointsU,pointsV); - Handle_Geom_BSplineSurface hSurf; - - //pc.EnableSmoothing(true, 0.1f, 0.5f, 0.2f, 0.3f); - pc.EnableSmoothing(true, 0.1f, 1.0f, 0.0f, 0.0f); - hSurf = pc.CreateSurface(clPoints, 5, true, 1.0); - if (!hSurf.IsNull()) { - return new Part::BSplineSurfacePy(new Part::GeomBSplineSurface(hSurf)); + + Reen::BSplineParameterCorrection pc(orderU,orderV,pointsU,pointsV); + Handle_Geom_BSplineSurface hSurf; + + //pc.EnableSmoothing(true, 0.1f, 0.5f, 0.2f, 0.3f); + pc.EnableSmoothing(true, 0.1f, 1.0f, 0.0f, 0.0f); + hSurf = pc.CreateSurface(clPoints, 5, true, 1.0); + if (!hSurf.IsNull()) { + return new Part::BSplineSurfacePy(new Part::GeomBSplineSurface(hSurf)); } PyErr_SetString(PyExc_Exception, "Computation of B-Spline surface failed"); @@ -75,8 +79,31 @@ static PyObject * approxSurface(PyObject *self, PyObject *args) } PY_CATCH; } +#if defined(PCL_FOUND) +static PyObject * +triangulate(PyObject *self, PyObject *args) +{ + PyObject *pcObj; + if (!PyArg_ParseTuple(args, "O!", &(Points::PointsPy::Type), &pcObj)) + return NULL; + + Points::PointsPy* pPoints = static_cast(pcObj); + Points::PointKernel* points = pPoints->getPointKernelPtr(); + + Mesh::MeshObject* mesh = new Mesh::MeshObject(); + SurfaceTriangulation tria(*points, *mesh); + tria.perform(); + + return new Mesh::MeshPy(mesh); +} +#endif + /* registration table */ struct PyMethodDef ReverseEngineering_methods[] = { {"approxSurface" , approxSurface, 1}, +#if defined(PCL_FOUND) + {"triangulate" , triangulate, 1}, +#endif {NULL, NULL} /* end of table marker */ }; + diff --git a/src/Mod/ReverseEngineering/App/CMakeLists.txt b/src/Mod/ReverseEngineering/App/CMakeLists.txt index 4cbf02bc4..20a6d8575 100644 --- a/src/Mod/ReverseEngineering/App/CMakeLists.txt +++ b/src/Mod/ReverseEngineering/App/CMakeLists.txt @@ -4,6 +4,10 @@ else(MSVC) add_definitions(-DHAVE_LIMITS_H -DHAVE_CONFIG_H) endif(MSVC) +if (PCL_FOUND) + add_definitions(-DPCL_FOUND) +endif(PCL_FOUND) + include_directories( ${CMAKE_SOURCE_DIR}/src ${Boost_INCLUDE_DIRS} @@ -11,6 +15,8 @@ include_directories( ${PYTHON_INCLUDE_PATH} ${XERCESC_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} + ${EIGEN3_INCLUDE_DIR} + ${PCL_INCLUDE_DIRS} ) link_directories(${OCC_LIBRARY_DIR}) @@ -18,7 +24,12 @@ link_directories(${OCC_LIBRARY_DIR}) set(Reen_LIBS Part Mesh + Points FreeCADApp + ${PCL_COMMON_LIBRARIES} + ${PCL_KDTREE_LIBRARIES} + ${PCL_FEATURES_LIBRARIES} + ${PCL_SURFACE_LIBRARIES} ) SET(Reen_SRCS @@ -26,6 +37,8 @@ SET(Reen_SRCS AppReverseEngineeringPy.cpp ApproxSurface.cpp ApproxSurface.h + SurfaceTriangulation.cpp + SurfaceTriangulation.h PreCompiled.cpp PreCompiled.h ) diff --git a/src/Mod/ReverseEngineering/App/PreCompiled.h b/src/Mod/ReverseEngineering/App/PreCompiled.h index eaaea1f87..603a5afff 100644 --- a/src/Mod/ReverseEngineering/App/PreCompiled.h +++ b/src/Mod/ReverseEngineering/App/PreCompiled.h @@ -29,12 +29,14 @@ // Exporting of App classes #ifdef FC_OS_WIN32 # define ReenExport __declspec(dllexport) -# define PartExport __declspec(dllimport) +# define PartExport __declspec(dllimport) # define MeshExport __declspec(dllimport) +# define PointsExport __declspec(dllimport) #else // for Linux # define ReenExport -# define PartExport -# define MeshExport +# define PartExport +# define MeshExport +# define PointsExport #endif #ifdef _PreComp_ @@ -51,15 +53,15 @@ #include // OpenCasCade -#include -#include +#include +#include #include #include #include #include #include #include -#include +#include #include #include #include diff --git a/src/Mod/ReverseEngineering/App/SurfaceTriangulation.cpp b/src/Mod/ReverseEngineering/App/SurfaceTriangulation.cpp new file mode 100644 index 000000000..dfcd2a4ee --- /dev/null +++ b/src/Mod/ReverseEngineering/App/SurfaceTriangulation.cpp @@ -0,0 +1,159 @@ +/*************************************************************************** + * Copyright (c) 2012 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#include "SurfaceTriangulation.h" +#include +#include +#include +#include + +// http://svn.pointclouds.org/pcl/tags/pcl-1.5.1/test/ +#if defined(PCL_FOUND) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace pcl; +using namespace pcl::io; +using namespace std; +using namespace Reen; + +SurfaceTriangulation::SurfaceTriangulation(const Points::PointKernel& pts, Mesh::MeshObject& mesh) + : myPoints(pts), myMesh(mesh) +{ +} + +void SurfaceTriangulation::perform() +{ + PointCloud::Ptr cloud (new PointCloud); + PointCloud::Ptr cloud_with_normals (new PointCloud); + search::KdTree::Ptr tree; + search::KdTree::Ptr tree2; + + for (Points::PointKernel::const_iterator it = myPoints.begin(); it != myPoints.end(); ++it) { + cloud->push_back(PointXYZ(it->x, it->y, it->z)); + } + + // Create search tree + tree.reset (new search::KdTree (false)); + tree->setInputCloud (cloud); + + // Normal estimation + NormalEstimation n; + PointCloud::Ptr normals (new PointCloud ()); + n.setInputCloud (cloud); + //n.setIndices (indices[B); + n.setSearchMethod (tree); + n.setKSearch (20); + n.compute (*normals); + + // Concatenate XYZ and normal information + pcl::concatenateFields (*cloud, *normals, *cloud_with_normals); + + // Create search tree + tree2.reset (new search::KdTree); + tree2->setInputCloud (cloud_with_normals); + + // Init objects + GreedyProjectionTriangulation gp3; + + // Set parameters + gp3.setInputCloud (cloud_with_normals); + gp3.setSearchMethod (tree2); + gp3.setSearchRadius (2.025); + gp3.setMu (2.5); + gp3.setMaximumNearestNeighbors (100); + gp3.setMaximumSurfaceAngle(M_PI/4); // 45 degrees + gp3.setMinimumAngle(M_PI/18); // 10 degrees + gp3.setMaximumAngle(2*M_PI/3); // 120 degrees + gp3.setNormalConsistency(false); + + // Reconstruct + PolygonMesh mesh; + gp3.reconstruct (mesh); + + // number of points + int nr_points = mesh.cloud.width * mesh.cloud.height; + int point_size = mesh.cloud.data.size () / nr_points; + // number of faces for header + int nr_faces = mesh.polygons.size (); + + MeshCore::MeshPointArray points; + points.reserve(nr_points); + MeshCore::MeshFacetArray facets; + facets.reserve(nr_faces); + + // get vertices + MeshCore::MeshPoint vertex; + for (int i = 0; i < nr_points; ++i) { + int xyz = 0; + for (size_t d = 0; d < mesh.cloud.fields.size(); ++d) { + int c = 0; + // adding vertex + if ((mesh.cloud.fields[d].datatype == sensor_msgs::PointField::FLOAT32) && ( + mesh.cloud.fields[d].name == "x" || + mesh.cloud.fields[d].name == "y" || + mesh.cloud.fields[d].name == "z")) + { + float value; + memcpy (&value, &mesh.cloud.data[i * point_size + mesh.cloud.fields[d].offset + c * sizeof (float)], sizeof (float)); + vertex[xyz] = value; + if (++xyz == 3) { + points.push_back(vertex); + break; + } + } + } + } + // get faces + MeshCore::MeshFacet face; + for(int i = 0; i < nr_faces; i++) { + face._aulPoints[0] = mesh.polygons[i].vertices[0]; + face._aulPoints[1] = mesh.polygons[i].vertices[1]; + face._aulPoints[2] = mesh.polygons[i].vertices[2]; + facets.push_back(face); + } + + MeshCore::MeshKernel kernel; + kernel.Adopt(points, facets, true); + myMesh.swap(kernel); + myMesh.harmonizeNormals(); + + // Additional vertex information + //std::vector parts = gp3.getPartIDs(); + //std::vector states = gp3.getPointStates(); +} + +#endif // PCL_FOUND + diff --git a/src/Mod/ReverseEngineering/App/SurfaceTriangulation.h b/src/Mod/ReverseEngineering/App/SurfaceTriangulation.h new file mode 100644 index 000000000..5310c2d35 --- /dev/null +++ b/src/Mod/ReverseEngineering/App/SurfaceTriangulation.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (c) 2012 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef REEN_SURFACETRIANGULATION_H +#define REEN_SURFACETRIANGULATION_H + +namespace Points {class PointKernel;} +namespace Mesh {class MeshObject;} + +namespace Reen { + +class SurfaceTriangulation +{ +public: + SurfaceTriangulation(const Points::PointKernel&, Mesh::MeshObject&); + void perform(); + +private: + const Points::PointKernel& myPoints; + Mesh::MeshObject& myMesh; +}; + +} // namespace Reen + +#endif // REEN_SURFACETRIANGULATION_H +