diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 31858bea..f60defb9 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -63,7 +63,12 @@ jobs: - name: cxxlib shell: bash run: | - git describe --tags > src/git-tag.txt + if [[ "${GITHUB_REF}" == refs/tags/* ]]; then + version="${GITHUB_REF##*/}" + else + version="$(date '+%Y.%-m.%-d').dev${GITHUB_RUN_NUMBER}" + fi + echo "${version}" > src/git-tag.txt if [ "${{ matrix.docker_image }}" != "" ]; then export OCL_DOCKER_IMAGE="${{ matrix.docker_image }}" @@ -146,7 +151,12 @@ jobs: - name: nodejslib shell: bash run: | - git describe --tags > src/git-tag.txt + if [[ "${GITHUB_REF}" == refs/tags/* ]]; then + version="${GITHUB_REF##*/}" + else + version="$(date '+%Y.%-m.%-d')-dev.${GITHUB_RUN_NUMBER}" + fi + echo "${version}" > src/git-tag.txt if [ "${{ matrix.docker_image }}" != "" ]; then export OCL_DOCKER_IMAGE="${{ matrix.docker_image }}" @@ -262,7 +272,7 @@ jobs: version="$(date '+%Y.%-m.%-d').dev${GITHUB_RUN_NUMBER}" fi sed -i.bak "s/^version = .*/version = \"${version}\"/g" pyproject.toml && rm pyproject.toml.bak - git describe --tags > src/git-tag.txt + echo "${version}" > src/git-tag.txt - name: Set up QEMU uses: docker/setup-qemu-action@v2 if: matrix.architecture == 'aarch64' @@ -435,7 +445,11 @@ jobs: shell: bash run: | mkdir dist - mv prebuilds/*-cxx-*/* dist + zip -r dist/linux-cxx-x86_64.zip prebuilds/linux-cxx-x86_64 + zip -r dist/macos-cxx-arm64.zip prebuilds/macos-cxx-arm64 + zip -r dist/macos-cxx-x86_64.zip prebuilds/macos-cxx-x86_64 + zip -r dist/windows-cxx-ia32.zip prebuilds/windows-cxx-ia32 + zip -r dist/windows-cxx-x64.zip prebuilds/windows-cxx-x64 - name: Release uses: softprops/action-gh-release@v1 with: diff --git a/CMakeLists.txt b/CMakeLists.txt index 965d4d7b..60569de3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,6 @@ -project(OpenCAMLib) cmake_minimum_required(VERSION 3.15...3.25) +project(OpenCAMLib LANGUAGES CXX) + set( CMAKE_SOURCE_DIR ${CMAKE_SOURCE_DIR}/src ) add_subdirectory( src ) diff --git a/examples/cpp/test/test_example.cpp b/examples/cpp/test/test_example.cpp index cb07ce2c..706c0da0 100644 --- a/examples/cpp/test/test_example.cpp +++ b/examples/cpp/test/test_example.cpp @@ -9,19 +9,68 @@ #include #include #include +#include +#include +#include #include #include #include +void printXYZ(ocl::Point point) +{ + // printf("X%g ", round(point.x * 100000.0) / 100000.0); + // printf("Y%g ", round(point.y * 100000.0) / 100000.0); + // printf("Z%g", round(point.z * 100000.0) / 100000.0); +} + +void linear(ocl::Point point) +{ + // printf("G01 "); + // printXYZ(point); + // printf("\n"); +} + void moveSafely(ocl::Point point) { - printf("G00 Z10\n"); - printf("G00 "); - printf("X%g ", round(point.x * 100000.0) / 100000.0); - printf("Y%g\n", round(point.y * 100000.0) / 100000.0); - printf("G01 "); - printf("Z%g", round(point.z * 100000.0) / 100000.0); - printf(" F50\n"); + // printf("G00 Z10\n"); + // printf("G00 "); + // printf("X%g ", round(point.x * 100000.0) / 100000.0); + // printf("Y%g\n", round(point.y * 100000.0) / 100000.0); + // printf("G01 "); + // printf("Z%g", round(point.z * 100000.0) / 100000.0); + // printf(" F50\n"); +} + +void printPoints(std::vector points) +{ + for (auto j = 0; j < points.size(); j++) + { + auto point = points[j]; + if (j == 0) + moveSafely(point); + else + linear(point); + } +} + +void printPoints(std::vector points) +{ + for (auto j = 0; j < points.size(); j++) + { + auto point = points[j]; + if (j == 0) + moveSafely(point); + else + linear(point); + } +} + +void printLoops(std::vector> loops) +{ + for (auto i = 0; i < loops.size(); i++) + { + printPoints(loops[i]); + } } void waterline(ocl::STLSurf surface, ocl::MillingCutter *cutter, double z, double sampling) @@ -29,25 +78,14 @@ void waterline(ocl::STLSurf surface, ocl::MillingCutter *cutter, double z, doubl ocl::Waterline wl = ocl::Waterline(); wl.setSTL(surface); wl.setCutter(cutter); - wl.setZ(z); wl.setSampling(sampling); - wl.run(); - auto loops = wl.getLoops(); - // std::cout << "loops: " << loops.size() << "\n"; - for (auto i = 0; i < loops.size(); i++) + for (double h = 0; h < z; h = h + 0.1) { - for (auto j = 0; j < loops[i].size(); j++) - { - auto point = loops[i][j]; - if (j == 0) { - moveSafely(point); - } else { - printf("G01 "); - printf("X%g ", round(point.x * 100000.0) / 100000.0); - printf("Y%g ", round(point.y * 100000.0) / 100000.0); - printf("Z%g\n", round(point.z * 100000.0) / 100000.0); - } - } + wl.reset(); + wl.setZ(h); + wl.run(); + auto loops = wl.getLoops(); + printLoops(loops); } } @@ -56,26 +94,15 @@ void adaptiveWaterline(ocl::STLSurf surface, ocl::MillingCutter *cutter, double ocl::AdaptiveWaterline awl = ocl::AdaptiveWaterline(); awl.setSTL(surface); awl.setCutter(cutter); - awl.setZ(z); awl.setSampling(sampling); awl.setMinSampling(minSampling); - awl.run(); - auto loops = awl.getLoops(); - // std::cout << "loops: " << loops.size() << "\n"; - for (auto i = 0; i < loops.size(); i++) + for (double h = 0; h < z; h = h + 0.1) { - for (auto j = 0; j < loops[i].size(); j++) - { - auto point = loops[i][j]; - if (j == 0) { - moveSafely(point); - } else { - printf("G01 "); - printf("X%g ", round(point.x * 100000.0) / 100000.0); - printf("Y%g ", round(point.y * 100000.0) / 100000.0); - printf("Z%g\n", round(point.z * 100000.0) / 100000.0); - } - } + awl.reset(); + awl.setZ(h); + awl.run(); + auto loops = awl.getLoops(); + printLoops(loops); } } @@ -85,23 +112,12 @@ void pathDropCutter(ocl::STLSurf surface, ocl::MillingCutter *cutter, double sam pdc.setSTL(surface); pdc.setCutter(cutter); pdc.setPath(path); - pdc.setZ(0); pdc.setSampling(sampling); + pdc.reset(); + pdc.setZ(0); pdc.run(); auto points = pdc.getPoints(); - // std::cout << "points: " << points.size() << "\n"; - for (auto i = 0; i < points.size(); i++) - { - auto point = points[i]; - if (i == 0) { - moveSafely(point); - } else { - printf("G01 "); - printf("X%g ", round(point.x * 100000.0) / 100000.0); - printf("Y%g ", round(point.y * 100000.0) / 100000.0); - printf("Z%g\n", round(point.z * 100000.0) / 100000.0); - } - } + printPoints(points); } void adaptivePathDropCutter(ocl::STLSurf surface, ocl::MillingCutter *cutter, double sampling, double minSampling, ocl::Path *path) @@ -110,54 +126,70 @@ void adaptivePathDropCutter(ocl::STLSurf surface, ocl::MillingCutter *cutter, do apdc.setSTL(surface); apdc.setCutter(cutter); apdc.setPath(path); - apdc.setZ(0); apdc.setSampling(sampling); apdc.setMinSampling(minSampling); + apdc.reset(); + apdc.setZ(0); apdc.run(); auto points = apdc.getPoints(); - // std::cout << "points: " << points.size() << "\n"; - for (auto i = 0; i < points.size(); i++) - { - auto point = points[i]; - if (i == 0) { - moveSafely(point); - } else { - printf("G01 "); - printf("X%g ", round(point.x * 100000.0) / 100000.0); - printf("Y%g ", round(point.y * 100000.0) / 100000.0); - printf("Z%g\n", round(point.z * 100000.0) / 100000.0); - } - } + printPoints(points); } int main() { - // std::cout << "ocl version: " << ocl::version() << "\n"; - // std::cout << "max threads: " << ocl::max_threads() << "\n"; + std::cout << "ocl version: " << ocl::version() << "\n"; + std::cout << "max threads: " << ocl::max_threads() << "\n"; ocl::STLSurf surface = ocl::STLSurf(); std::wstring stlPath = L"../../../../stl/gnu_tux_mod.stl"; ocl::STLReader(stlPath, surface); - // std::cout << "surface size: " << surface.size() << "\n"; - ocl::CylCutter cutter = ocl::CylCutter(4, 20); - double z = 1; + std::cout << "surface size: " << surface.size() << "\n"; + + ocl::CylCutter cylCutter = ocl::CylCutter(0.4, 10); + ocl::BallCutter ballCutter = ocl::BallCutter(4, 20); + ocl::BullCutter bullCutter = ocl::BullCutter(4, 0.05, 20); + ocl::ConeCutter coneCutter = ocl::ConeCutter(4, 0.05, 20); + std::vector cutters; + cutters.push_back(&cylCutter); + cutters.push_back(&ballCutter); + cutters.push_back(&bullCutter); + cutters.push_back(&coneCutter); + double z = 0.5; double sampling = 0.1; - waterline(surface, &cutter, z, sampling); - // std::cout << "waterline done.\n"; - double minSampling = 0.001; - ocl::CylCutter cutter2 = ocl::CylCutter(4, 20); - adaptiveWaterline(surface, &cutter2, z, sampling, minSampling); - // std::cout << "adaptivewaterline done.\n"; + for (auto cutter : cutters) + { + std::cout << "WL + Cutter: " << cutter->str() << "\n"; + waterline(surface, cutter, z, sampling); + } + double minSampling = 0.01; + for (auto cutter : cutters) + { + std::cout << "AWL + Cutter: " << cutter->str() << "\n"; + adaptiveWaterline(surface, cutter, z, sampling, minSampling); + } ocl::Path path = ocl::Path(); - ocl::Point p1 = ocl::Point(-2, 4, 0); - ocl::Point p2 = ocl::Point(11, 4, 0); - ocl::Line l = ocl::Line(p1, p2); - path.append(l); - ocl::CylCutter cutter3 = ocl::CylCutter(4, 20); - pathDropCutter(surface, &cutter3, sampling, &path); - // std::cout << "pathdropcutter done.\n"; - ocl::CylCutter cutter4 = ocl::CylCutter(4, 20); - adaptivePathDropCutter(surface, &cutter4, sampling, minSampling, &path); - // std::cout << "adaptivepathdropcutter done.\n"; - return 0; -} + int i = 0; + for (double y = 0; y <= 0.2; y = y + 0.1) + { + bool ltr = ((int)i % 2) == 0; + ocl::Point p1 = ocl::Point(ltr ? -2 : 11, y, 0); + ocl::Point p2 = ocl::Point(ltr ? 11 : -2, y, 0); + ocl::Line l = ocl::Line(p1, p2); + path.append(l); + ocl::Point p3 = ocl::Point(ltr ? 11 : -2, y + 1, 0); + ocl::Line l2 = ocl::Line(p2, p3); + path.append(l2); + i++; + } + for (auto cutter : cutters) + { + std::cout << "PDC + Cutter: " << cutter->str() << "\n"; + pathDropCutter(surface, cutter, sampling, &path); + } + for (auto cutter : cutters) + { + std::cout << "APDC: " << cutter->str() << "\n"; + adaptivePathDropCutter(surface, cutter, sampling, minSampling, &path); + } + return 0; +} \ No newline at end of file diff --git a/install.sh b/install.sh index fc1d9a13..3d7f51b0 100755 --- a/install.sh +++ b/install.sh @@ -31,7 +31,7 @@ Options: --boost-python-version Set the python version to look for when compiling Boost (only valid when using --install-boost and --boost-with-python) --python-executable Set a custom path (or name of) the Python executable (only valid when using --build-library python) - --python-prefix Set the python prefix, this will be passed to CMake as Python_ROOT_DIR, to make sure CMake is using the correct Python installation. (only valid when using --build-library python) + --python-prefix Set the python prefix, this will be passed to CMake as Python3_ROOT_DIR, to make sure CMake is using the correct Python installation. (only valid when using --build-library python) --python-pip-install Uses "pip install ." to compile and install the Python library (only valid when using --build-library python) --platform Set the platform, for when auto-detection doesn't work (one of: windows, macos, linux) @@ -121,7 +121,7 @@ if [ "${OCL_BUILD_TYPE}" = "debug" ]; then build_type="Debug" build_type_lower="debug" else - build_type="Release" + build_type="RelWithDebInfo" build_type_lower="release" fi build_dir="${project_dir}/build/${OCL_BUILD_LIBRARY}/${build_type_lower}" @@ -541,7 +541,7 @@ ${OCL_BOOST_PREFIX:+"-D BOOST_ROOT=${OCL_BOOST_PREFIX} "}" -D Boost_ADDITIONAL_VERSIONS="${boost_additional_versions}" \ -D CMAKE_INSTALL_PREFIX="${OCL_INSTALL_PREFIX:-"${install_prefix_fallback}"}" \ ${OCL_DISABLE_OPENMP:+"-DUSE_OPENMP=OFF"} \ - ${OCL_PYTHON_PREFIX:+"-DPython_ROOT_DIR=${OCL_PYTHON_PREFIX}"} \ + ${OCL_PYTHON_PREFIX:+"-DPython3_ROOT_DIR=${OCL_PYTHON_PREFIX}"} \ ${OCL_BOOST_PREFIX:+"-DBOOST_ROOT=${OCL_BOOST_PREFIX}"} \ ../../.. set +x diff --git a/pyproject.toml b/pyproject.toml index 28550fac..20be73f3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,8 +42,8 @@ wheel.packages = ["src/pythonlib/opencamlib"] [tool.scikit-build.cmake.define] BUILD_PY_LIB = "ON" -USE_OPENMP = "ON" Boost_ADDITIONAL_VERSIONS = "1.80.0;1.79.0;1.78.0;1.77.0;1.76.0;1.75.0;1.74.0;1.73.0;1.72.0;1.71.0;1.70.0" +BUILD_DOC = "OFF" [tool.cibuildwheel] build = ["cp37*", "cp38*", "cp39*", "cp310*", "cp311*"] @@ -63,3 +63,4 @@ before-build = "cd {package} && bash ./install.sh --install-boost --boost-with-p archs = ["x86_64", "arm64"] before-all = "cd {package} && bash ./install.sh --install-ci-deps" before-build = "cd {package} && bash ./install.sh --install-boost --boost-with-python --python-executable python" +repair-wheel-command = "python src/pythonlib/delocate-wheel.py --require-archs {delocate_archs} -w {dest_dir} -v {wheel}" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 124fadb6..4915cea5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -project(OpenCAMLib) +project(OpenCAMLib LANGUAGES CXX) set(CMAKE_VERBOSE_MAKEFILE ON) @@ -45,7 +45,7 @@ option(USE_OPENMP "Use OpenMP for parallel computation" ON) option(VERSION_STRING - "Set version string" OFF) + "Set version string") option(USE_PY_3 "Use Python V3" ON) @@ -90,6 +90,12 @@ if(UNIX) endif() endif() +include(CheckIPOSupported) +check_ipo_supported(RESULT got_ipo_support) +if(got_ipo_support) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) +endif() + include_directories(${CMAKE_CURRENT_BINARY_DIR}) set(Boost_DEBUG ON CACHE BOOL "boost-debug") @@ -142,26 +148,10 @@ if(USE_OPENMP) set(OpenMP_omp_LIBRARY "$ENV{OPENMP_PREFIX_MACOS}/lib/libomp.dylib") include_directories("$ENV{OPENMP_PREFIX_MACOS}/include") else() - find_program(brew brew) - if(brew) - message(STATUS "Found homebrew at ${brew}.") - execute_process(COMMAND "${brew}" --prefix libomp - RESULT_VARIABLE brew_libomp_found - OUTPUT_VARIABLE brew_libomp OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) - if(brew_libomp_found EQUAL 0) - message(STATUS "Found libomp at ${brew_libomp}.") - set(OpenMP_C_FLAGS "-Xpreprocessor -fopenmp") - set(OpenMP_C_LIB_NAMES "omp") - set(OpenMP_CXX_FLAGS "-Xpreprocessor -fopenmp") - set(OpenMP_CXX_LIB_NAMES "omp") - set(OpenMP_omp_LIBRARY "${brew_libomp}/lib/libomp.dylib") - include_directories("${brew_libomp}/include") - endif() - else() - message(STATUS "Homebrew not found, please install homebrew and run `brew install libomp` for OpenMP support.") - endif() + list(APPEND CMAKE_PREFIX_PATH "/usr/local/opt/libomp") + list(APPEND CMAKE_PREFIX_PATH "/opt/homebrew/opt/libomp") endif() - endif(APPLE) + endif() find_package(OpenMP REQUIRED) if(OPENMP_FOUND) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") diff --git a/src/algo/adaptivewaterline.cpp b/src/algo/adaptivewaterline.cpp index 40767c97..393ac507 100644 --- a/src/algo/adaptivewaterline.cpp +++ b/src/algo/adaptivewaterline.cpp @@ -51,23 +51,16 @@ AdaptiveWaterline::AdaptiveWaterline() { subOp.push_back( new FiberPushCutter() ); subOp[0]->setXDirection(); subOp[1]->setYDirection(); - nthreads=1; + nthreads = 1; #ifdef _OPENMP - nthreads = omp_get_num_procs(); - // omp_set_dynamic(0); - // omp_set_nested(1); + nthreads = omp_get_num_procs(); #endif sampling = 1.0; min_sampling = 0.1; cosLimit = 0.999; } -AdaptiveWaterline::~AdaptiveWaterline() { - // std::cout << "~AdaptiveWaterline(): subOp.size()= " << subOp.size() <<"\n"; - // delete subOp[1]; - // delete subOp[0]; - // subOp.clear(); -} +AdaptiveWaterline::~AdaptiveWaterline() {} void AdaptiveWaterline::run() { adaptive_sampling_run(); @@ -86,7 +79,6 @@ void AdaptiveWaterline::adaptive_sampling_run() { maxy = surf->bb.maxpt.y + 2*cutter->getRadius(); Line* line = new Line( Point(minx,miny,zh) , Point(maxx,maxy,zh) ); Span* linespan = new LineSpan(*line); - #ifdef _WIN32 // OpenMP task not supported with the version 2 of VS2013 OpenMP #pragma omp parallel sections { @@ -144,7 +136,6 @@ void AdaptiveWaterline::adaptive_sampling_run() { delete line; delete linespan; - } @@ -152,8 +143,9 @@ void AdaptiveWaterline::xfiber_adaptive_sample(const Span* span, double start_t, const double mid_t = start_t + (stop_t-start_t)/2.0; // mid point sample assert( mid_t > start_t ); assert( mid_t < stop_t ); //std::cout << "xfiber sample= ( " << start_t << " , " << stop_t << " ) \n"; - Point mid_p1 = Point( minx, span->getPoint( mid_t ).y, zh ); - Point mid_p2 = Point( maxx, span->getPoint( mid_t ).y, zh ); + double mid_y = span->getPoint( mid_t ).y; + Point mid_p1 = Point( minx, mid_y, zh ); + Point mid_p2 = Point( maxx, mid_y, zh ); Fiber mid_f = Fiber( mid_p1, mid_p2 ); subOp[0]->run( mid_f ); double fw_step = fabs( start_f.p1.y - stop_f.p1.y ) ; @@ -167,15 +159,16 @@ void AdaptiveWaterline::xfiber_adaptive_sample(const Span* span, double start_t, } } else { xfibers.push_back(stop_f); - } + } } void AdaptiveWaterline::yfiber_adaptive_sample(const Span* span, double start_t, double stop_t, Fiber start_f, Fiber stop_f) { const double mid_t = start_t + (stop_t-start_t)/2.0; // mid point sample assert( mid_t > start_t ); assert( mid_t < stop_t ); //std::cout << "yfiber sample= ( " << start_t << " , " << stop_t << " ) \n"; - Point mid_p1 = Point( span->getPoint( mid_t ).x, miny, zh ); - Point mid_p2 = Point( span->getPoint( mid_t ).x, maxy, zh ); + double mid_x = span->getPoint( mid_t ).x; + Point mid_p1 = Point( mid_x, miny, zh ); + Point mid_p2 = Point( mid_x, maxy, zh ); Fiber mid_f = Fiber( mid_p1, mid_p2 ); subOp[1]->run( mid_f ); double fw_step = fabs( start_f.p1.x - stop_f.p1.x ) ; @@ -188,7 +181,7 @@ void AdaptiveWaterline::yfiber_adaptive_sample(const Span* span, double start_t, yfiber_adaptive_sample( span, mid_t , stop_t, mid_f , stop_f ); } } else { - yfibers.push_back(stop_f); + yfibers.push_back(stop_f); } } @@ -213,7 +206,7 @@ bool AdaptiveWaterline::flat( Fiber& start, Fiber& mid, Fiber& stop ) const { } } return true; - } + } } diff --git a/src/algo/clsurface.hpp b/src/algo/clsurface.hpp index 241f7f8d..603eab86 100644 --- a/src/algo/clsurface.hpp +++ b/src/algo/clsurface.hpp @@ -238,9 +238,9 @@ class CutterLocationSurface : public Operation { // now loop through edges again: f_edges = g.face_edges(f); assert( f_edges.size() == 8 ); - BOOST_FOREACH( CLSEdge e, f_edges ) { - std::cout << e << "\n"; - } + // BOOST_FOREACH( CLSEdge e, f_edges ) { + // std::cout << e << "\n"; + // } } virtual void run() { diff --git a/src/algo/fiber.cpp b/src/algo/fiber.cpp index cb34bc9e..66ce67b8 100644 --- a/src/algo/fiber.cpp +++ b/src/algo/fiber.cpp @@ -82,7 +82,7 @@ void Fiber::addInterval(Interval& i) { } overlaps.push_back(i); // now build a new interval from i and the overlaps - Interval sumint; + Interval sumint; BOOST_FOREACH(Interval intr, overlaps) { sumint.updateLower( intr.lower, intr.lower_cc ); sumint.updateUpper( intr.upper, intr.upper_cc ); @@ -95,7 +95,8 @@ void Fiber::addInterval(Interval& i) { double Fiber::tval(Point& p) const { // fiber is f = p1 + t * (p2-p1) // t = (f-p1).dot(p2-p1) / (p2-p1).dot(p2-p1) - return (p-p1).dot(p2-p1) / (p2-p1).dot(p2-p1); + Point p2minp1 = p2 - p1; + return (p-p1).dot(p2minp1) / (p2minp1).dot(p2minp1); } Point Fiber::point(double t) const { diff --git a/src/algo/fiberpushcutter.cpp b/src/algo/fiberpushcutter.cpp index 3665859c..a213d05f 100644 --- a/src/algo/fiberpushcutter.cpp +++ b/src/algo/fiberpushcutter.cpp @@ -37,10 +37,6 @@ namespace ocl FiberPushCutter::FiberPushCutter() { nCalls = 0; - nthreads = 1; -#ifdef _OPENMP - nthreads = omp_get_num_procs(); // figure out how many cores we have -#endif cutter = NULL; bucketSize = 1; root = new KDTree(); @@ -96,7 +92,7 @@ void FiberPushCutter::pushCutter2(Fiber& f) { for ( it=tris->begin() ; it!=it_end ; ++it) { i = new Interval(); cutter->pushCutter(f,*i,*it); - f.addInterval(*i); + f.addInterval(*i); ++nCalls; delete i; } diff --git a/src/algo/smart_weave.cpp b/src/algo/smart_weave.cpp index a57dca0a..9167594d 100644 --- a/src/algo/smart_weave.cpp +++ b/src/algo/smart_weave.cpp @@ -52,7 +52,7 @@ std::pair SmartWeave::find_neighbor_vertices( VertexPair v_pair, // this is the new smarter build() which uses less RAM void SmartWeave::build() { - std::cout << " SimpleWeave::build()... \n"; + // std::cout << " SmartWeave::build()... \n"; // this adds all CL-vertices from x-intervals // it also populates the xi.intersections_fibers set of intersecting y-fibers @@ -296,7 +296,7 @@ void SmartWeave::add_all_edges() { std::vector vertices = g.vertices(); - std::cout << "There are " << vertices.size() << " vertices.\n"; + // std::cout << "There are " << vertices.size() << " vertices.\n"; BOOST_FOREACH( Vertex& vertex, vertices ) { if( (g[vertex].type == INT) || (g[vertex].type == FULLINT) ) { std::vector adjacent_vertices; diff --git a/src/algo/zigzag.hpp b/src/algo/zigzag.hpp index 1b59fa7f..10a87bf7 100644 --- a/src/algo/zigzag.hpp +++ b/src/algo/zigzag.hpp @@ -54,9 +54,9 @@ class ZigZag { // calculate a reasonable maximum/minimum step-over dist Point perp = dir.xyPerp(); perp.xyNormalize(); - std::cout << " minpt = " << bb.minpt << std::endl; - std::cout << " maxpt = " << bb.maxpt << std::endl; - std::cout << " perp = " << perp << std::endl; + // std::cout << " minpt = " << bb.minpt << std::endl; + // std::cout << " maxpt = " << bb.maxpt << std::endl; + // std::cout << " perp = " << perp << std::endl; double max_d = (bb.maxpt - origin).dot( perp ); double min_d = (bb.minpt - origin).dot( perp ); if ( max_d < min_d ) { @@ -65,7 +65,7 @@ class ZigZag { min_d = tmp; } //int n = min_d / stepOver; // some safety margin here... (required?) - std::cout << " max_d= " << max_d << " min_d= "<< min_d << std::endl; + // std::cout << " max_d= " << max_d << " min_d= "<< min_d << std::endl; std::vector distances; for (double d = min_d ; d <= max_d ; d += stepOver ) { diff --git a/src/common/brent_zero.hpp b/src/common/brent_zero.hpp index abe5a60c..e486c40d 100644 --- a/src/common/brent_zero.hpp +++ b/src/common/brent_zero.hpp @@ -82,12 +82,12 @@ double brent_zero( double a, double b, double eps, double t, ErrObj* ell) { p = s*(2.0*m*a*(q-r)-(b-a)*(r-1.0)); q = (q-1.0)*(r-1.0)*(s-1.0); } - + if (p>0.0) q=-q; else p=-p; // make p negative - + s=e; e=d; if ( (2.0*p < (3.0*m*q-fabs(tol*q))) && (perror(b); // f(b); - - if ( ((fb>0.0) && (fc>0.0)) || ((fb<=0.0) && (fc<=0.0)) ) { + + if (std::signbit(fb) == std::signbit(fc)) + { + // if ((fb > 0.0 && fc > 0.0) || (fb <= 0.0 && fc <= 0.0)) { // fb and fc have the same sign c = a; // so change c to a fc = fa; diff --git a/src/common/kdtree.hpp b/src/common/kdtree.hpp index 97b8f8be..11fc9c25 100644 --- a/src/common/kdtree.hpp +++ b/src/common/kdtree.hpp @@ -225,32 +225,45 @@ class KDTree { for (unsigned int m=0;m t.bb[ dimensions[m] ]) - minval[ dimensions[m] ] = t.bb[ dimensions[m] ]; + if (maxval[point] < tbbpoint ) + maxval[point] = tbbpoint; + if (minval[point] > tbbpoint) + minval[point] = tbbpoint; } } - } - std::vector spreads;// calculate the spread along each dimension + } + + double max = 0; + double maxM = 0; + // std::vector spreads;// calculate the spread along each dimension for (unsigned int m=0;m max) { + max = val; + maxM = m; + } + // spreads.push_back( new Spread(dimensions[m] , + // maxval[dimensions[m]]-minval[dimensions[m]], + // minval[dimensions[m]] ) ); }// priority-queue could also be used ?? - assert( !spreads.empty() ); + // assert( !spreads.empty() ); //std::cout << " spreads.size()=" << spreads.size() << "\n"; - std::sort(spreads.begin(), spreads.end(), Spread::spread_compare); // sort the list - Spread* s= new Spread(*spreads[0]); // this is the one we want to return - while(!spreads.empty()) delete spreads.back(), spreads.pop_back(); // delete the others + // std::sort(spreads.begin(), spreads.end(), Spread::spread_compare); // sort the list + // Spread* s= new Spread(*spreads[0]); // this is the one we want to return + // while(!spreads.empty()) delete spreads.back(), spreads.pop_back(); // delete the others //std::cout << "calc_spread() done\n"; - return s; // select the biggest spread and return + return new Spread(dimensions[maxM] , + maxval[dimensions[maxM]]-minval[dimensions[maxM]], + minval[dimensions[maxM]] ); + // return s; // select the biggest spread and return } // end tris->size != 0 } // end spread(); diff --git a/src/common/numeric.cpp b/src/common/numeric.cpp index 004c3719..99644a12 100644 --- a/src/common/numeric.cpp +++ b/src/common/numeric.cpp @@ -150,7 +150,7 @@ bool xy_line_line_intersection( const Point& p1, const Point& p2, double& v, // => // [ (p2-p1).x -(p4-p3).x ] [ v ] = [ (p3-p1).x ] // [ (p2-p1).y -(p4-p3).y ] [ t ] = [ (p3-p1).y ] - return two_by_two_solver( (p2-p1).x , -(p4-p3).x , (p2-p1).y , -(p4-p3).y, (p3-p1).x, (p3-p1).y, v, t); + return two_by_two_solver(p2.x - p1.x, -(p4.x - p3.x), p2.y - p1.y, -(p4.y - p3.y), (p3.x - p1.x), p3.y - p1.y, v, t); } diff --git a/src/cutters/ballcutter.cpp b/src/cutters/ballcutter.cpp index 6316e1a5..20b911bc 100644 --- a/src/cutters/ballcutter.cpp +++ b/src/cutters/ballcutter.cpp @@ -120,7 +120,7 @@ bool BallCutter::calcCCandUpdateInterval( double t, const Point& p1, const Point CCPoint cc_tmp = cl_center.closestPoint(p1,p2); // cc-point on the edge, point on edge closest to center cc_tmp.type = EDGE_BALL; // require contact with lower hemishphere - return i.update_ifCCinEdgeAndTrue( t, cc_tmp, p1, p2, ((cl_center-cc_tmp).z >=0) ); + return i.update_ifCCinEdgeAndTrue( t, cc_tmp, p1, p2, (cl_center.z-cc_tmp.z >=0) ); } std::string BallCutter::str() const { diff --git a/src/cutters/ellipse.cpp b/src/cutters/ellipse.cpp index 76c88a60..9c5c64c7 100644 --- a/src/cutters/ellipse.cpp +++ b/src/cutters/ellipse.cpp @@ -193,7 +193,7 @@ int Ellipse::solver_brent() { return iters; } else if ( fabs( error(bpos) ) < OE_ERROR_TOLERANCE ) { // or bpos might be the solution? EllipsePosition1 = bpos; - find_EllipsePosition2(); + find_EllipsePosition2(); return iters; } // neither apos nor bpos is the solution @@ -232,41 +232,45 @@ bool AlignedEllipse::aligned_solver( const Fiber& f ) { bool found_positive=false; bool found_negative=false; tmp.setDiangle( xyVectorToDiangle(s1,t1) ); - if (error(tmp.diangle) > 0) { + double err = error(tmp.diangle); + if (err > 0) { found_positive = true; apos = tmp; - } else if (error(tmp.diangle) < 0) { + } else if (err < 0) { found_negative = true; bpos = tmp; } tmp.setDiangle( xyVectorToDiangle(s1,-t1) ); - if (error(tmp.diangle) > 0) { + err = error(tmp.diangle); + if (err > 0) { found_positive = true; apos = tmp; } - else if (error(tmp.diangle) < 0) { + else if (err < 0) { found_negative = true; bpos = tmp; - } + } tmp.setDiangle( xyVectorToDiangle(-s1,t1) ); - if (error(tmp.diangle) > 0) { + err = error(tmp.diangle); + if (err > 0) { found_positive = true; apos = tmp; } - else if (error(tmp.diangle) < 0) { + else if (err < 0) { found_negative = true; bpos = tmp; } tmp.setDiangle( xyVectorToDiangle(-s1,-t1) ); - if (error(tmp.diangle) > 0) { + err = error(tmp.diangle); + if (err > 0) { found_positive = true; apos = tmp; } - else if (error(tmp.diangle) < 0) { + else if (err < 0) { found_negative = true; bpos = tmp; } - + if (found_positive) { if (found_negative) { assert( this->error(apos.diangle) * this->error(bpos.diangle) < 0.0 ); // root is now bracketed. diff --git a/src/cxxlib/cxxlib.cmake b/src/cxxlib/cxxlib.cmake index 12f030cd..7c97e5d3 100644 --- a/src/cxxlib/cxxlib.cmake +++ b/src/cxxlib/cxxlib.cmake @@ -33,6 +33,17 @@ target_include_directories(ocl $ ) +# disable /GL and enable /LTCG (see https://github.com/luxonis/depthai-core/issues/334) +if(WIN32 AND MSVC) # AND CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS + get_target_property(_INTER_OPT ocl INTERPROCEDURAL_OPTIMIZATION) + if(_INTER_OPT) + message(STATUS "Workaround MSVC dll exports with INTERPROCEDURAL_OPTIMIZATION") + set_target_properties(ocl PROPERTIES INTERPROCEDURAL_OPTIMIZATION OFF) + target_link_options(ocl PRIVATE /LTCG) + endif() + unset(_INTER_OPT) +endif() + # link with Boost and optionally with OpenMP target_link_libraries(ocl PUBLIC Boost::boost) if(USE_OPENMP) @@ -50,6 +61,23 @@ install( PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) +if(APPLE) + target_compile_options(ocl PRIVATE -g) + # if(CMAKE_CXX_FLAGS MATCHES "-flto") + set(lto_object ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/ocl-lto.o) + set_property(TARGET ocl APPEND_STRING PROPERTY + LINK_FLAGS " -Wl,-object_path_lto -Wl,${lto_object}") + # endif() + add_custom_command(TARGET ocl POST_BUILD + COMMAND xcrun dsymutil $ + COMMAND xcrun strip -Sl $) + install( + FILES $.dSYM + DESTINATION ${CMAKE_INSTALL_LIBDIR}/opencamlib + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ + ) +endif() + # this install the cmake targets install( EXPORT ocltargets @@ -71,17 +99,18 @@ install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/cmake/${PROJECT_NAME} ) -if(USE_OPENMP) - if(APPLE) - # copy libomp into install directory - install( - FILES ${OpenMP_omp_LIBRARY} - DESTINATION ${CMAKE_INSTALL_LIBDIR}/opencamlib - PERMISSIONS OWNER_READ GROUP_READ WORLD_READ - ) - # fix loader path - add_custom_command(TARGET ocl POST_BUILD - COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change `otool -L $ | grep libomp | cut -d ' ' -f1 | xargs echo` "@loader_path/libomp.dylib" $ - ) - endif() +if(USE_OPENMP AND APPLE) + # add homebrew libomp paths to the INSTALL_RPATH, and the @loader_path last as a fallback. + set_target_properties(ocl PROPERTIES + INSTALL_RPATH "/opt/homebrew/opt/libomp/lib;/usr/local/opt/libomp/lib;@loader_path") + # copy libomp into install directory + install( + FILES ${OpenMP_CXX_LIBRARIES} + DESTINATION ${CMAKE_INSTALL_LIBDIR}/opencamlib + PERMISSIONS OWNER_READ GROUP_READ WORLD_READ + ) + # fix loader path + add_custom_command(TARGET ocl POST_BUILD + COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change `otool -L $ | grep libomp | cut -d ' ' -f1 | xargs echo` "@rpath/libomp.dylib" $ + ) endif() \ No newline at end of file diff --git a/src/geo/point.cpp b/src/geo/point.cpp index daf3d33b..c161c28c 100644 --- a/src/geo/point.cpp +++ b/src/geo/point.cpp @@ -73,8 +73,9 @@ double Point::dot(const Point &p) const { } void Point::normalize() { - if (this->norm() != 0.0) - *this *=(1/this->norm()); + double norm = this->norm(); + if (norm != 0.0) + *this *=(1/norm); } double Point::xyNorm() const { @@ -217,30 +218,24 @@ bool Point::isRight(const Point &p1, const Point &p2) const if (t > 0.00000000000001) /// \todo FIXME: hardcoded magic number... return true; else - return false; + return false; } bool Point::isInside(const Triangle &t) const { - // point in triangle test - // http://www.blackpawn.com/texts/pointinpoly/default.html - - Point v0 = t.p[2] - t.p[0]; - Point v1 = t.p[1] - t.p[0]; - Point v2 = *this - t.p[0]; - - double dot00 = v0.dot(v0); - double dot01 = v0.dot(v1); - double dot02 = v0.dot(v2); - double dot11 = v1.dot(v1); - double dot12 = v1.dot(v2); - - double invD = 1.0 / ( dot00 *dot11 - dot01*dot01 ); - // barycentric coordinates - double u = (dot11 * dot02 - dot01 * dot12) * invD; - double v = (dot00 * dot12 - dot01 * dot02) * invD; + Point p = *this; + Point a = t.p[0]; + Point b = t.p[1]; + Point c = t.p[2]; - // Check if point is in triangle - return (u > 0.0) && (v > 0.0) && (u + v < 1.0); + // Compute barycentric coordinates + double u = (a.y * c.x - a.x * c.y + (c.y - a.y) * p.x + (a.x - c.x) * p.y) + / (a.y * c.x - a.x * c.y + (c.y - a.y) * b.x + (a.x - c.x) * b.y); + + double v = (a.x * b.y - a.y * b.x + (a.y - b.y) * p.x + (b.x - a.x) * p.y) + / (a.x * b.y - a.y * b.x + (a.y - b.y) * c.x + (b.x - a.x) * c.y); + + // Check if point is inside triangle + return u > 0.0 && v > 0.0 && (u + v) < 1.0; } bool Point::isInside(const Point& p1, const Point& p2) const { @@ -248,19 +243,15 @@ bool Point::isInside(const Point& p1, const Point& p2) const { // p1 + t*(p2-p1) = p // p1*(p2-p1) + t * (p2-p1)*(p2-p1) = p*(p2-p1) // t = (p - p1 )*(p2-p1) / (p2-p1)*(p2-p1) - double t = (*this - p1).dot( p2-p1 ) / (p2-p1).dot(p2-p1); - if (t > 1.0) - return false; - else if (t < 0.0) + Point p2minusp1 = p2 - p1; + Point thisminusp1 = (*this - p1); + double t = thisminusp1.dot(p2minusp1) / p2minusp1.dot(p2minusp1); + if (t > 1.0 || t < 0.0) { return false; - else - return true; + } + return true; } - - - - /* **************** Operators *************** * see * http://www.cs.caltech.edu/courses/cs11/material/cpp/donnie/cpp-ops.html diff --git a/src/geo/stlreader.cpp b/src/geo/stlreader.cpp index 48797f80..505cf3b1 100644 --- a/src/geo/stlreader.cpp +++ b/src/geo/stlreader.cpp @@ -121,11 +121,7 @@ namespace ocl #ifdef WIN32 sscanf_s(str, " vertex %f %f %f", &(x[vertex][0]), &(x[vertex][1]), &(x[vertex][2])); #else - std::istringstream ss(str); - ss.imbue(std::locale("C")); - while(ss.peek() == ' ') ss.seekg(1, ios_base::cur); - ss.seekg(std::string("vertex").size(), ios_base::cur); - ss >> x[vertex][0] >> x[vertex][1] >> x[vertex][2]; + sscanf(str, " vertex %f %f %f", &(x[vertex][0]), &(x[vertex][1]), &(x[vertex][2])); #endif vertex++; if(vertex > 2)vertex = 2; @@ -135,11 +131,7 @@ namespace ocl #ifdef WIN32 sscanf_s(str, " facet normal %f %f %f", &(n[0]), &(n[1]), &(n[2])); #else - std::istringstream ss(str); - ss.imbue(std::locale("C")); - while(ss.peek() == ' ') ss.seekg(1, ios_base::cur); - ss.seekg(std::string("facet normal").size(), ios_base::cur); - ss >> n[0] >> n[1] >> n[2]; + sscanf(str, " facet normal %f %f %f", &(n[0]), &(n[1]), &(n[2])); #endif vertex = 0; } diff --git a/src/pythonlib/delocate-wheel.py b/src/pythonlib/delocate-wheel.py new file mode 100644 index 00000000..ef35709d --- /dev/null +++ b/src/pythonlib/delocate-wheel.py @@ -0,0 +1,147 @@ +#!python +""" Copy, relink library dependencies for wheel +Overwrites the wheel in-place by default +""" +# vim: ft=python +from __future__ import absolute_import, division, print_function + +import logging +import os +import sys +from optparse import Option, OptionParser +from os.path import basename, exists, expanduser +from os.path import join as pjoin +from typing import List, Optional, Text + +from delocate import __version__, delocate_wheel + + +def filter_system_libs(libname): + return not (libname.startswith('/usr/lib') or + libname.startswith('/System') or + libname.find('libomp.dylib') >= 0) + +def main() -> None: + parser = OptionParser( + usage="%s WHEEL_FILENAME\n\n" % sys.argv[0] + __doc__, + version="%prog " + __version__, + ) + parser.add_options( + [ + Option( + "-L", + "--lib-sdir", + action="store", + type="string", + default=".dylibs", + help="Subdirectory in packages to store copied libraries", + ), + Option( + "-w", + "--wheel-dir", + action="store", + type="string", + help=( + "Directory to store delocated wheels (default is to " + "overwrite input)" + ), + ), + Option( + "-v", + "--verbose", + action="count", + help=( + "Show a more verbose report of progress and failure." + " Additional flags show even more info, up to -vv." + ), + default=0, + ), + Option( + "-k", + "--check-archs", + action="store_true", + help="Check architectures of depended libraries", + ), + Option( + "-d", + "--dylibs-only", + action="store_true", + help="Only analyze files with known dynamic library extensions", + ), + Option( + "--require-archs", + action="store", + type="string", + help=( + "Architectures that all wheel libraries should " + "have (from 'intel', 'i386', 'x86_64', 'i386,x86_64'" + "'universal2', 'x86_64,arm64')" + ), + ), + Option( + "--executable-path", + action="store", + type="string", + default=os.path.dirname(sys.executable), + help=( + "The path used to resolve @executable_path in dependencies" + ), + ), + Option( + "--ignore-missing-dependencies", + action="store_true", + help=( + "Skip dependencies which couldn't be found and delocate " + "as much as possible" + ), + ), + ] + ) + (opts, wheels) = parser.parse_args() + if len(wheels) < 1: + parser.print_help() + sys.exit(1) + logging.basicConfig( + level={0: logging.WARNING, 1: logging.INFO, 2: logging.DEBUG}.get( + opts.verbose, logging.DEBUG + ) + ) + multi = len(wheels) > 1 + if opts.wheel_dir: + wheel_dir = expanduser(opts.wheel_dir) + if not exists(wheel_dir): + os.makedirs(wheel_dir) + else: + wheel_dir = None + require_archs: Optional[List[Text]] = None + if opts.require_archs is None: + require_archs = [] if opts.check_archs else None + elif "," in opts.require_archs: + require_archs = [s.strip() for s in opts.require_archs.split(",")] + else: + require_archs = opts.require_archs + # lib_filt_func = "dylibs-only" if opts.dylibs_only else None + for wheel in wheels: + if multi or opts.verbose: + print("Fixing: " + wheel) + if wheel_dir: + out_wheel = pjoin(wheel_dir, basename(wheel)) + else: + out_wheel = wheel + copied = delocate_wheel( + wheel, + out_wheel, + lib_filt_func=filter_system_libs, + lib_sdir=opts.lib_sdir, + require_archs=require_archs, + executable_path=opts.executable_path, + ignore_missing=opts.ignore_missing_dependencies, + ) + if opts.verbose and len(copied): + print("Copied to package {0} directory:".format(opts.lib_sdir)) + copy_lines = [" " + name for name in sorted(copied)] + print("\n".join(copy_lines)) + + +if __name__ == "__main__": + main() diff --git a/src/pythonlib/pythonlib.cmake b/src/pythonlib/pythonlib.cmake index 28a95fbd..87b47e89 100644 --- a/src/pythonlib/pythonlib.cmake +++ b/src/pythonlib/pythonlib.cmake @@ -1,5 +1,10 @@ -find_package(Python COMPONENTS Interpreter Development.Module REQUIRED) -find_package(Boost COMPONENTS python${Python_VERSION_MAJOR}${Python_VERSION_MINOR} REQUIRED) +find_package(Python3 COMPONENTS Interpreter Development.Module REQUIRED) +if(Python3_FOUND) + message(STATUS "Found Python: " ${Python3_VERSION}) + message(STATUS "Python libraries: " ${Python3_LIBRARIES}) + message(STATUS "Python executable: " ${Python3_EXECUTABLE}) +endif() +find_package(Boost COMPONENTS python${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR} REQUIRED) # include dirs include_directories(${PROJECT_SOURCE_DIR}/cutters) @@ -10,7 +15,7 @@ include_directories(${PROJECT_SOURCE_DIR}/common) include_directories(${PROJECT_SOURCE_DIR}) # this makes the ocl Python module -Python_add_library( +Python3_add_library( ocl MODULE pythonlib/ocl_cutters.cpp @@ -28,8 +33,8 @@ PRIVATE ocl_cutters ocl_geo ocl_algo - Boost::python${Python_VERSION_MAJOR}${Python_VERSION_MINOR} - Python::Module + Boost::python${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR} + Python3::Module ) if(USE_OPENMP) @@ -45,14 +50,17 @@ if(NOT SKBUILD) endif() if(USE_OPENMP AND APPLE) + # add homebrew libomp paths to the INSTALL_RPATH, and the @loader_path last as a fallback. + set_target_properties(ocl PROPERTIES + INSTALL_RPATH "/opt/homebrew/opt/libomp/lib;/usr/local/opt/libomp/lib;@loader_path") # copy libomp into install directory install( - FILES ${OpenMP_omp_LIBRARY} + FILES ${OpenMP_CXX_LIBRARIES} DESTINATION "opencamlib" PERMISSIONS OWNER_READ GROUP_READ WORLD_READ ) # fix loader path add_custom_command(TARGET ocl POST_BUILD - COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change `otool -L $ | grep libomp | cut -d ' ' -f1 | xargs echo` "@loader_path/libomp.dylib" $ + COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change `otool -L $ | grep libomp | cut -d ' ' -f1 | xargs echo` "@rpath/libomp.dylib" $ ) endif()