remove parallel processing, replace mesh generation with getting facets
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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})
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user