remove parallel processing, replace mesh generation with getting facets

This commit is contained in:
Eric Trombly
2020-03-30 11:18:36 -05:00
parent 3f36f55853
commit fbc266c158
4 changed files with 122 additions and 133 deletions

View File

@@ -44,6 +44,7 @@
#include <TopoDS.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopoDS_Iterator.hxx>
#include <TopExp_Explorer.hxx>
@@ -53,6 +54,7 @@
#include <BRepAdaptor_HCompCurve.hxx>
#include <Approx_Curve3d.hxx>
#include <BRepAdaptor_HCurve.hxx>
#include <BRepMesh_IncrementalMesh.hxx>
#include "CommandPy.h"
#include "PathPy.h"
@@ -103,6 +105,9 @@ public:
Module() : Py::ExtensionModule<Module>("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<Part::TopoShapePy*>(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;

View File

@@ -84,10 +84,6 @@
# include <TopTools_HSequenceOfShape.hxx>
#endif
// TODO: remove omp and console
#include <Base/Console.h>
#include <thread>
#include <mutex>
#include <Base/Exception.h>
#include <Base/Tools.h>
@@ -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<shared_ptr<Area> > Area::makeSections(
area->setPlane(face.Moved(locInverse));
if(project) {
typedef std::list<Shape> 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<std::mutex> lockGuard(m);
area->add(it->shape.Moved(wloc).Moved(locInverse),it->op);
}
}
};
if(projectedShapes.size() < n)
{
worker(projectedShapes.begin(), projectedShapes.end());
} else {
std::vector<std::thread> 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::Shape> Area::getProjectedShapes(const gp_Trsf &trsf, bool invers
TopLoc_Location loc(trsf);
TopLoc_Location locInverse(loc.Inverted());
typedef std::list<Shape> 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<std::mutex> 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<std::thread> 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

View File

@@ -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})

View File

@@ -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