diff --git a/src/Mod/Path/App/AppPathPy.cpp b/src/Mod/Path/App/AppPathPy.cpp index 381ef87ef6..bc34de944c 100644 --- a/src/Mod/Path/App/AppPathPy.cpp +++ b/src/Mod/Path/App/AppPathPy.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +54,7 @@ #include #include #include +#include #include "CommandPy.h" #include "PathPy.h" @@ -103,6 +105,9 @@ public: Module() : Py::ExtensionModule("Path") { + add_varargs_method("getFacets",&Module::getFacets, + "getFacets(shape): simplified mesh generation" + ); add_varargs_method("write",&Module::write, "write(object,filename): Exports a given path object to a GCode file" ); @@ -142,6 +147,49 @@ public: private: + Py::Object getFacets(const Py::Tuple& args) + { + PyObject *shape; + PyObject *list = PyList_New(0); + if (!PyArg_ParseTuple(args.ptr(), "O", &shape)) + throw Py::Exception(); + auto theShape = static_cast(shape)->getTopoShapePtr()->getShape(); + for(TopExp_Explorer ex(theShape, TopAbs_FACE); ex.More(); ex.Next()) + { + TopoDS_Face currentFace = TopoDS::Face(ex.Current()); + TopLoc_Location loc; + Handle(Poly_Triangulation) facets = BRep_Tool::Triangulation(currentFace, loc); + const TopAbs_Orientation anOrientation = currentFace.Orientation(); + bool flip = (anOrientation == TopAbs_REVERSED); + if(!facets.IsNull()){ + auto nodes = facets->Nodes(); + auto triangles = facets->Triangles(); + for(int i = 1; i <= triangles.Length(); i++){ + Standard_Integer n1,n2,n3; + triangles[i].Get(n1, n2, n3); + gp_Pnt p1 = nodes[n1]; + gp_Pnt p2 = nodes[n2]; + gp_Pnt p3 = nodes[n3]; + p1.Transform(loc.Transformation()); + p2.Transform(loc.Transformation()); + p3.Transform(loc.Transformation()); + PyObject *t1 = PyTuple_Pack(3, PyFloat_FromDouble(p1.X()), PyFloat_FromDouble(p1.Y()), PyFloat_FromDouble(p1.Z())); + PyObject *t2 = PyTuple_Pack(3, PyFloat_FromDouble(p2.X()), PyFloat_FromDouble(p2.Y()), PyFloat_FromDouble(p2.Z())); + PyObject *t3 = PyTuple_Pack(3, PyFloat_FromDouble(p3.X()), PyFloat_FromDouble(p3.Y()), PyFloat_FromDouble(p3.Z())); + PyObject *points; + if(flip) + { + points = PyTuple_Pack(3, t2, t1, t3); + } else { + points = PyTuple_Pack(3, t1, t2, t3); + } + PyList_Append(list, points); + } + } + } + return Py::asObject(list); + } + Py::Object write(const Py::Tuple& args) { char* Name; diff --git a/src/Mod/Path/App/Area.cpp b/src/Mod/Path/App/Area.cpp index a27db4bb88..ea61c9049a 100644 --- a/src/Mod/Path/App/Area.cpp +++ b/src/Mod/Path/App/Area.cpp @@ -84,10 +84,6 @@ # include #endif -// TODO: remove omp and console -#include -#include -#include #include #include @@ -1294,10 +1290,8 @@ int Area::project(TopoDS_Shape &shape_out, showShape(joiner.comp,"pre_project"); - auto new_params = params; - Area area(new_params); + Area area(params); area.myParams.SectionCount = 0; - area.myParams.Offset = 0.0; area.myParams.PocketMode = 0; area.myParams.Explode = false; @@ -1308,7 +1302,8 @@ int Area::project(TopoDS_Shape &shape_out, area.myParams.Coplanar = CoplanarNone; area.myProjecting = true; area.add(joiner.comp, OperationUnion); - const TopoDS_Shape shape = area.getShape(); + const TopoDS_Shape &shape = area.getShape(); + area.myParams.dump("project"); showShape(shape,"projected"); @@ -1483,46 +1478,11 @@ std::vector > Area::makeSections( area->setPlane(face.Moved(locInverse)); if(project) { - typedef std::list container; - typedef container::iterator iter; - std::mutex m; - - unsigned int n = std::thread::hardware_concurrency(); - Base::Console().Error("makeSections Threads: %d Shapes: %d\n", n, projectedShapes.size()); - auto worker = [&m, &d, &area, &locInverse] (iter begin, iter end) { - Base::Console().Error("In worker (# items: %d)\n", std::distance(begin, end)); - for (auto it = begin; it != end; it++) { - gp_Trsf t; - t.SetTranslation(gp_Vec(0,0,-d)); - TopLoc_Location wloc(t); - { - std::lock_guard lockGuard(m); - area->add(it->shape.Moved(wloc).Moved(locInverse),it->op); - } - } - }; - if(projectedShapes.size() < n) - { - worker(projectedShapes.begin(), projectedShapes.end()); - } else { - std::vector threads(n); - const size_t chunk_size = projectedShapes.size() / n; - - size_t thread_num = 1; - for(auto it = std::begin(threads); it != std::end(threads) -1; ++it) - { - auto begin = projectedShapes.begin(); - std::advance(begin, thread_num * chunk_size); - auto end = begin; - if(thread_num == n - 1) // last thread iterates the remaining sequence - end = projectedShapes.end(); - else - std::advance(end, chunk_size); - *it = std::thread(worker, begin, end); - thread_num++; - } - for (auto&& i : threads) - i.join(); + for(const auto &s : projectedShapes) { + gp_Trsf t; + t.SetTranslation(gp_Vec(0,0,-d)); + TopLoc_Location wloc(t); + area->add(s.shape.Moved(wloc).Moved(locInverse),s.op); } sections.push_back(area); break; @@ -1640,55 +1600,18 @@ std::list Area::getProjectedShapes(const gp_Trsf &trsf, bool invers TopLoc_Location loc(trsf); TopLoc_Location locInverse(loc.Inverted()); - typedef std::list container; - typedef container::const_iterator iter; - std::mutex m; - int mySkippedShapes = 0; - - unsigned int n = std::thread::hardware_concurrency(); - Base::Console().Error("getProjectedShapes Threads: %d Shapes: %d\n", n, myShapes.size()); - auto worker = [&m, &inverse, &loc, &ret, &locInverse, &mySkippedShapes] (iter begin,iter end, const AreaParams& myParams) { - Base::Console().Error("In worker (# items: %d)\n", std::distance(begin, end)); - for (auto it = begin; it != end; it++) { - TopoDS_Shape out; - int skipped = Area::project(out,it->shape.Moved(loc), &myParams); - { - std::lock_guard lockGuard(m); - if(skipped < 0) { - ++mySkippedShapes; - continue; - }else - mySkippedShapes += skipped; - if(!out.IsNull()) - ret.emplace_back(it->op,inverse?out.Moved(locInverse):out); - } - - } - }; - if(myShapes.size() < n) - { - worker(myShapes.begin(), myShapes.end(), myParams); - } else { - std::vector threads(n); - const size_t chunk_size = myShapes.size() / n; - - size_t thread_num = 1; - for(auto it = std::begin(threads); it != std::end(threads) -1; ++it) - { - auto begin = myShapes.begin(); - std::advance(begin, thread_num * chunk_size); - auto end = begin; - if(thread_num == n - 1) // last thread iterates the remaining sequence - end = myShapes.end(); - else - std::advance(end, chunk_size); - *it = std::thread(worker, begin, end, myParams); - thread_num++; - } - for (auto&& i : threads) - i.join(); + mySkippedShapes = 0; + for(auto &s : myShapes) { + TopoDS_Shape out; + int skipped = Area::project(out,s.shape.Moved(loc),&myParams); + if(skipped < 0) { + ++mySkippedShapes; + continue; + }else + mySkippedShapes += skipped; + if(!out.IsNull()) + ret.emplace_back(s.op,inverse?out.Moved(locInverse):out); } - if(mySkippedShapes) AREA_WARN("skipped " << mySkippedShapes << " sub shapes during projection"); return ret; @@ -3531,4 +3454,4 @@ const AreaStaticParams &Area::getDefaultParams() { #if defined(__clang__) # pragma clang diagnostic pop -#endif +#endif \ No newline at end of file diff --git a/src/Mod/Path/App/CMakeLists.txt b/src/Mod/Path/App/CMakeLists.txt index 69a260d61b..72cc976129 100644 --- a/src/Mod/Path/App/CMakeLists.txt +++ b/src/Mod/Path/App/CMakeLists.txt @@ -118,10 +118,8 @@ SOURCE_GROUP("Module" FILES ${Mod_SRCS}) # SOURCE_GROUP("KDL" FILES ${KDL_SRCS} ${KDL_HPPS} ${UTIL_SRCS} ${UTIL_HPPS} ) #endif(WIN32) -find_package(Threads REQUIRED) - add_library(Path SHARED ${Path_SRCS}) -target_link_libraries(Path ${Path_LIBS} Threads::Threads) +target_link_libraries(Path ${Path_LIBS}) if(FREECAD_USE_PCH) add_definitions(-D_PreComp_) @@ -133,4 +131,4 @@ endif(FREECAD_USE_PCH) SET_BIN_DIR(Path Path /Mod/Path) SET_PYTHON_PREFIX_SUFFIX(Path) -INSTALL(TARGETS Path DESTINATION ${CMAKE_INSTALL_LIBDIR}) +INSTALL(TARGETS Path DESTINATION ${CMAKE_INSTALL_LIBDIR}) \ No newline at end of file diff --git a/src/Mod/Path/PathScripts/PathSurface.py b/src/Mod/Path/PathScripts/PathSurface.py index 7514da410e..d2f9682fa4 100644 --- a/src/Mod/Path/PathScripts/PathSurface.py +++ b/src/Mod/Path/PathScripts/PathSurface.py @@ -365,9 +365,11 @@ class ObjectSurface(PathOp.ObjectOp): def opExecute(self, obj): '''opExecute(obj) ... process surface operation''' PathLog.track() - #import cProfile - #pr = cProfile.Profile() - #pr.enable() + ######## DEBUG + import cProfile + pr = cProfile.Profile() + pr.enable() + ######## self.modelSTLs = list() self.safeSTLs = list() @@ -606,8 +608,10 @@ class ObjectSurface(PathOp.ObjectOp): del self.deflection execTime = time.time() - startTime - #pr.disable() - #pr.dump_stats("/mnt/files/profile.cprof") + ####### DEBUG + pr.disable() + pr.dump_stats("/mnt/files/profile.cprof") + ############# PathLog.info('Operation time: {} sec.'.format(execTime)) return True @@ -1421,26 +1425,49 @@ class ObjectSurface(PathOp.ObjectOp): # PathLog.debug(f" -self.modelTypes[{m}] == 'M'") if self.modelTypes[m] == 'M': - mesh = M.Mesh + #TODO: get this to work with new mesher + facets = M.Mesh.Facets else: # base.Shape.tessellate(0.05) # 0.5 original value # mesh = MeshPart.meshFromShape(base.Shape, Deflection=self.deflection) - mesh = MeshPart.meshFromShape(Shape=M.Shape, - LinearDeflection=obj.LinearDeflection.Value, - AngularDeflection=obj.AngularDeflection.Value, - Relative=False) + #facets = MeshPart.meshFromShape(Shape=M.Shape, + # LinearDeflection=obj.LinearDeflection.Value, + # AngularDeflection=obj.AngularDeflection.Value, + # Relative=False) + facets = Path.getFacets(M.Shape) + + stl = ocl.STLSurf() + if self.modelSTLs[m] is True: stl = ocl.STLSurf() - for f in mesh.Facets: - p = f.Points[0] - q = f.Points[1] - r = f.Points[2] - t = ocl.Triangle(ocl.Point(p[0], p[1], p[2]), - ocl.Point(q[0], q[1], q[2]), - ocl.Point(r[0], r[1], r[2])) - stl.addTriangle(t) - self.modelSTLs[m] = stl + + if obj.Algorithm == 'OCL Dropcutter': + for tri in facets: + #p = tri.Points[0] + #q = tri.Points[1] + #r = tri.Points[2] + #t = ocl.Triangle(ocl.Point(p[0], p[1], p[2]), + # ocl.Point(q[0], q[1], q[2]), + # ocl.Point(r[0], r[1], r[2])) + t = ocl.Triangle(ocl.Point(tri[0][0], tri[0][1], tri[0][2]), + ocl.Point(tri[1][0], tri[1][1], tri[1][2]), + ocl.Point(tri[2][0], tri[2][1], tri[2][2])) + stl.addTriangle(t) + self.modelSTLs[m] = stl + elif obj.Algorithm == 'OCL Waterline': + for tri in facets: + #p = f.Points[0] + #q = f.Points[1] + #r = f.Points[2] + #t = ocl.Triangle(ocl.Point(p[0], p[1], p[2] + obj.DepthOffset.Value), + # ocl.Point(q[0], q[1], q[2] + obj.DepthOffset.Value), + # ocl.Point(r[0], r[1], r[2] + obj.DepthOffset.Value)) + t = ocl.Triangle(ocl.Point(tri[0][0], tri[0][1], tri[0][2] + obj.DepthOffset.Value), + ocl.Point(tri[1][0], tri[1][1], tri[1][2] + obj.DepthOffset.Value), + ocl.Point(tri[2][0], tri[2][1], tri[2][2] + obj.DepthOffset.Value)) + stl.addTriangle(t) + self.modelSTLs[m] = stl return def _makeSafeSTL(self, JOB, obj, mdlIdx, faceShapes, voidShapes): @@ -1518,20 +1545,13 @@ class ObjectSurface(PathOp.ObjectOp): T.purgeTouched() self.tempGroup.addObject(T) - # Extract mesh from fusion - meshFuse = MeshPart.meshFromShape(Shape=fused, - LinearDeflection=obj.LinearDeflection.Value, - AngularDeflection=obj.AngularDeflection.Value, - Relative=False) - #time.sleep(0.2) + facets = Path.getFacets(fused) + stl = ocl.STLSurf() - for f in meshFuse.Facets: - p = f.Points[0] - q = f.Points[1] - r = f.Points[2] - t = ocl.Triangle(ocl.Point(p[0], p[1], p[2]), - ocl.Point(q[0], q[1], q[2]), - ocl.Point(r[0], r[1], r[2])) + for tri in facets: + t = ocl.Triangle(ocl.Point(tri[0][0], tri[0][1], tri[0][2]), + ocl.Point(tri[1][0], tri[1][1], tri[1][2]), + ocl.Point(tri[2][0], tri[2][1], tri[2][2])) stl.addTriangle(t) self.safeSTLs[mdlIdx] = stl