mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-12-04 00:01:07 -07:00
ENH: revert boolean tool to mcut
Change-Id: I1aca763869e107a996519cb74e025043407005f2 (cherry picked from commit f7865828cf4b7b3ab8987bf0fc3d45efad2f08fe)
This commit is contained in:
parent
b55a5b7556
commit
c7ed4e7e14
38 changed files with 39957 additions and 5 deletions
1148
src/mcut/source/bvh.cpp
Normal file
1148
src/mcut/source/bvh.cpp
Normal file
File diff suppressed because it is too large
Load diff
3058
src/mcut/source/frontend.cpp
Normal file
3058
src/mcut/source/frontend.cpp
Normal file
File diff suppressed because it is too large
Load diff
1411
src/mcut/source/hmesh.cpp
Normal file
1411
src/mcut/source/hmesh.cpp
Normal file
File diff suppressed because it is too large
Load diff
10634
src/mcut/source/kernel.cpp
Normal file
10634
src/mcut/source/kernel.cpp
Normal file
File diff suppressed because it is too large
Load diff
903
src/mcut/source/math.cpp
Normal file
903
src/mcut/source/math.cpp
Normal file
|
|
@ -0,0 +1,903 @@
|
|||
/**
|
||||
* Copyright (c) 2021-2022 Floyd M. Chitalu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* NOTE: This file is licensed under GPL-3.0-or-later (default).
|
||||
* A commercial license can be purchased from Floyd M. Chitalu.
|
||||
*
|
||||
* License details:
|
||||
*
|
||||
* (A) GNU General Public License ("GPL"); a copy of which you should have
|
||||
* recieved with this file.
|
||||
* - see also: <http://www.gnu.org/licenses/>
|
||||
* (B) Commercial license.
|
||||
* - email: floyd.m.chitalu@gmail.com
|
||||
*
|
||||
* The commercial license options is for users that wish to use MCUT in
|
||||
* their products for comercial purposes but do not wish to release their
|
||||
* software products under the GPL license.
|
||||
*
|
||||
* Author(s) : Floyd M. Chitalu
|
||||
*/
|
||||
|
||||
#include "mcut/internal/math.h"
|
||||
#include <algorithm> // std::sort
|
||||
#include <cstdlib>
|
||||
#include <tuple> // std::make_tuple std::get<>
|
||||
|
||||
|
||||
double square_root(const double& number)
|
||||
{
|
||||
#if !defined(MCUT_WITH_ARBITRARY_PRECISION_NUMBERS)
|
||||
return std::sqrt(number);
|
||||
#else
|
||||
arbitrary_precision_number_t out(number);
|
||||
mpfr_sqrt(out.get_mpfr_handle(), number.get_mpfr_handle(), arbitrary_precision_number_t::get_default_rounding_mode());
|
||||
return out;
|
||||
#endif // #if !defined(MCUT_WITH_ARBITRARY_PRECISION_NUMBERS)
|
||||
}
|
||||
|
||||
double absolute_value(const double& number)
|
||||
{
|
||||
#if !defined(MCUT_WITH_ARBITRARY_PRECISION_NUMBERS)
|
||||
return std::fabs(number);
|
||||
#else
|
||||
double out(number);
|
||||
mpfr_abs(out.get_mpfr_handle(), number.get_mpfr_handle(), arbitrary_precision_number_t::get_default_rounding_mode());
|
||||
return out;
|
||||
#endif // #if defined(MCUT_WITH_ARBITRARY_PRECISION_NUMBERS)
|
||||
}
|
||||
|
||||
sign_t sign(const double& number)
|
||||
{
|
||||
#if !defined(MCUT_WITH_ARBITRARY_PRECISION_NUMBERS)
|
||||
int s = (double(0) < number) - (number < double(0));
|
||||
sign_t result = sign_t::ZERO;
|
||||
if (s > 0) {
|
||||
result = sign_t::POSITIVE;
|
||||
} else if (s < 0) {
|
||||
result = sign_t::NEGATIVE;
|
||||
}
|
||||
return result;
|
||||
#else
|
||||
double out(number);
|
||||
int s = mpfr_sgn(number.get_mpfr_handle());
|
||||
sign_t result = sign_t::ZERO;
|
||||
if (s > 0) {
|
||||
result = sign_t::POSITIVE;
|
||||
} else if (s < 0) {
|
||||
result = sign_t::NEGATIVE;
|
||||
}
|
||||
return result;
|
||||
#endif // #if defined(MCUT_WITH_ARBITRARY_PRECISION_NUMBERS)
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const vec3& v)
|
||||
{
|
||||
return os << static_cast<double>(v.x()) << ", " << static_cast<double>(v.y()) << ", " << static_cast<double>(v.z());
|
||||
}
|
||||
|
||||
bool operator==(const vec3& a, const vec3& b)
|
||||
{
|
||||
return (a.x() == b.x()) && (a.y() == b.y()) && (a.z() == b.z());
|
||||
}
|
||||
|
||||
vec3 cross_product(const vec3& a, const vec3& b)
|
||||
{
|
||||
return vec3(
|
||||
a.y() * b.z() - a.z() * b.y(),
|
||||
a.z() * b.x() - a.x() * b.z(),
|
||||
a.x() * b.y() - a.y() * b.x());
|
||||
}
|
||||
|
||||
double orient2d(const vec2& pa, const vec2& pb, const vec2& pc)
|
||||
{
|
||||
const double pa_[2] = { static_cast<double>(pa.x()), static_cast<double>(pa.y()) };
|
||||
const double pb_[2] = { static_cast<double>(pb.x()), static_cast<double>(pb.y()) };
|
||||
const double pc_[2] = { static_cast<double>(pc.x()), static_cast<double>(pc.y()) };
|
||||
|
||||
return ::orient2d(pa_, pb_, pc_); // shewchuk predicate
|
||||
}
|
||||
|
||||
double orient3d(const vec3& pa, const vec3& pb, const vec3& pc,
|
||||
const vec3& pd)
|
||||
{
|
||||
const double pa_[3] = { static_cast<double>(pa.x()), static_cast<double>(pa.y()), static_cast<double>(pa.z()) };
|
||||
const double pb_[3] = { static_cast<double>(pb.x()), static_cast<double>(pb.y()), static_cast<double>(pb.z()) };
|
||||
const double pc_[3] = { static_cast<double>(pc.x()), static_cast<double>(pc.y()), static_cast<double>(pc.z()) };
|
||||
const double pd_[3] = { static_cast<double>(pd.x()), static_cast<double>(pd.y()), static_cast<double>(pd.z()) };
|
||||
|
||||
return ::orient3d(pa_, pb_, pc_, pd_); // shewchuk predicate
|
||||
}
|
||||
|
||||
#if 0
|
||||
void polygon_normal(vec3& normal, const vec3* vertices, const int num_vertices)
|
||||
{
|
||||
normal = vec3(0.0);
|
||||
for (int i = 0; i < num_vertices; ++i) {
|
||||
normal = normal + cross_product(vertices[i] - vertices[0], vertices[(i + 1) % num_vertices] - vertices[0]);
|
||||
}
|
||||
normal = normalize(normal);
|
||||
}
|
||||
#endif
|
||||
|
||||
int compute_polygon_plane_coefficients(vec3& normal, double& d_coeff,
|
||||
const vec3* polygon_vertices, const int polygon_vertex_count)
|
||||
{
|
||||
// compute polygon normal (http://cs.haifa.ac.il/~gordon/plane.pdf)
|
||||
normal = vec3(0.0);
|
||||
for (int i = 0; i < polygon_vertex_count - 1; ++i) {
|
||||
normal = normal + cross_product(polygon_vertices[i] - polygon_vertices[0], polygon_vertices[(i + 1) % polygon_vertex_count] - polygon_vertices[0]);
|
||||
}
|
||||
|
||||
// In our calculations we need the normal be be of unit length so that the d-coeff
|
||||
// represents the distance of the plane from the origin
|
||||
// normal = normalize(normal);
|
||||
|
||||
d_coeff = dot_product(polygon_vertices[0], normal);
|
||||
|
||||
double largest_component(0.0);
|
||||
double tmp(0.0);
|
||||
int largest_component_idx = 0;
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
tmp = absolute_value(normal[i]);
|
||||
if (tmp > largest_component) {
|
||||
largest_component = tmp;
|
||||
largest_component_idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
return largest_component_idx;
|
||||
}
|
||||
|
||||
// Intersect a line segment with a plane
|
||||
//
|
||||
// Return values:
|
||||
// 'p': The segment lies wholly within the plane.
|
||||
// 'q': The(first) q endpoint is on the plane (but not 'p').
|
||||
// 'r' : The(second) r endpoint is on the plane (but not 'p').
|
||||
// '0' : The segment lies strictly to one side or the other of the plane.
|
||||
// '1': The segment intersects the plane, and none of {p, q, r} hold.
|
||||
char compute_segment_plane_intersection(vec3& p, const vec3& normal, const double& d_coeff,
|
||||
const vec3& q, const vec3& r)
|
||||
{
|
||||
|
||||
// vec3 planeNormal;
|
||||
// double planeDCoeff;
|
||||
// planeNormalLargestComponent = compute_polygon_plane_coefficients(planeNormal, planeDCoeff, polygonVertices,
|
||||
// polygonVertexCount);
|
||||
|
||||
double num = d_coeff - dot_product(q, normal);
|
||||
const vec3 rq = (r - q);
|
||||
double denom = dot_product(rq, normal);
|
||||
|
||||
if (denom == double(0.0) /* Segment is parallel to plane.*/) {
|
||||
if (num == double(0.0)) { // 'q' is on plane.
|
||||
return 'p'; // The segment lies wholly within the plane
|
||||
} else {
|
||||
return '0';
|
||||
}
|
||||
}
|
||||
|
||||
double t = num / denom;
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
p[i] = q[i] + t * (r[i] - q[i]);
|
||||
}
|
||||
|
||||
if ((double(0.0) < t) && (t < double(1.0))) {
|
||||
return '1'; // The segment intersects the plane, and none of {p, q, r} hold
|
||||
} else if (num == double(0.0)) // t==0
|
||||
{
|
||||
return 'q'; // The (first) q endpoint is on the plane (but not 'p').
|
||||
} else if (num == denom) // t==1
|
||||
{
|
||||
return 'r'; // The (second) r endpoint is on the plane (but not 'p').
|
||||
} else {
|
||||
return '0'; // The segment lies strictly to one side or the other of the plane
|
||||
}
|
||||
}
|
||||
|
||||
bool determine_three_noncollinear_vertices(int& i, int& j, int& k, const std::vector<vec3>& polygon_vertices,
|
||||
|
||||
const vec3& polygon_normal, const int polygon_normal_largest_component)
|
||||
{
|
||||
const int polygon_vertex_count = (int)polygon_vertices.size();
|
||||
MCUT_ASSERT(polygon_vertex_count >= 3);
|
||||
|
||||
std::vector<vec2> x;
|
||||
project_to_2d(x, polygon_vertices, polygon_normal, polygon_normal_largest_component);
|
||||
MCUT_ASSERT(x.size() == (size_t)polygon_vertex_count);
|
||||
|
||||
/*
|
||||
NOTE: We cannot just use _any_/the first result of "colinear(x[i], x[j], x[k])" which returns true since
|
||||
any three points that are _nearly_ colinear (in the limit of floating point precision)
|
||||
will be found to be not colinear when using the exact predicate "orient2d".
|
||||
This would have implications "further down the line", where e.g. the three nearly colinear points
|
||||
are determined to be non-colinear (in the exact sense) but using them to evaluate
|
||||
operations like segment-plane intersection would then give a false positive.
|
||||
To overcome this, must find the three vertices of the polygon, which maximise non-colinearity.
|
||||
|
||||
NOTE: if the polygon has 3 vertices and they are indeed nearly colinear then answer is determined by the
|
||||
exact predicate (i.e. i j k = 0 1 2)
|
||||
*/
|
||||
|
||||
// get any three vertices that are not collinear
|
||||
i = 0;
|
||||
j = i + 1;
|
||||
k = j + 1;
|
||||
std::vector<std::tuple<int, int, int, double>> non_colinear_triplets;
|
||||
|
||||
for (; i < polygon_vertex_count; ++i) {
|
||||
for (; j < polygon_vertex_count; ++j) {
|
||||
for (; k < polygon_vertex_count; ++k) {
|
||||
double predRes;
|
||||
if (!collinear(x[i], x[j], x[k], predRes)) {
|
||||
non_colinear_triplets.emplace_back(std::make_tuple(i, j, k, predRes));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(non_colinear_triplets.begin(), non_colinear_triplets.end(),
|
||||
[](const std::tuple<int, int, int, double>& a, const std::tuple<int, int, int, double>& b) {
|
||||
return std::fabs(std::get<3>(a)) > std::fabs(std::get<3>(b));
|
||||
});
|
||||
|
||||
std::tuple<int, int, int, double> best_triplet = non_colinear_triplets.front(); // maximising non-colinearity
|
||||
|
||||
i = std::get<0>(best_triplet);
|
||||
j = std::get<1>(best_triplet);
|
||||
k = std::get<2>(best_triplet);
|
||||
|
||||
return !non_colinear_triplets.empty(); // need at least one non-colinear triplet
|
||||
}
|
||||
|
||||
char compute_segment_plane_intersection_type(const vec3& q, const vec3& r,
|
||||
const std::vector<vec3>& polygon_vertices,
|
||||
const vec3& polygon_normal,
|
||||
const int polygon_normal_largest_component)
|
||||
{
|
||||
// TODO: we could also return i,j and k so that "determine_three_noncollinear_vertices" is not called multiple times,
|
||||
// which we do to determine the type of intersection and the actual intersection point
|
||||
const int polygon_vertex_count = (int)polygon_vertices.size();
|
||||
// ... any three vertices that are not collinear
|
||||
int i = 0;
|
||||
int j = 1;
|
||||
int k = 2;
|
||||
if (polygon_vertex_count > 3) { // case where we'd have the possibility of noncollinearity
|
||||
bool b = determine_three_noncollinear_vertices(i, j, k, polygon_vertices, polygon_normal,
|
||||
polygon_normal_largest_component);
|
||||
|
||||
if (!b) {
|
||||
return '0'; // all polygon points are collinear
|
||||
}
|
||||
}
|
||||
|
||||
double qRes = orient3d(polygon_vertices[i], polygon_vertices[j], polygon_vertices[k], q);
|
||||
double rRes = orient3d(polygon_vertices[i], polygon_vertices[j], polygon_vertices[k], r);
|
||||
|
||||
if (qRes == double(0.0) && rRes == double(0.0)) {
|
||||
return 'p';
|
||||
} else if (qRes == double(0.0)) {
|
||||
return 'q';
|
||||
} else if (rRes == double(0.0)) {
|
||||
return 'r';
|
||||
} else if ((rRes < double(0.0) && qRes < double(0.0)) || (rRes > double(0.0) && qRes > double(0.0))) {
|
||||
return '0';
|
||||
} else {
|
||||
return '1';
|
||||
}
|
||||
}
|
||||
|
||||
char compute_segment_line_plane_intersection_type(const vec3& q, const vec3& r,
|
||||
const std::vector<vec3>& polygon_vertices,
|
||||
|
||||
const int polygon_normal_max_comp,
|
||||
const vec3& polygon_plane_normal)
|
||||
{
|
||||
const int polygon_vertex_count = (int)polygon_vertices.size();
|
||||
// ... any three vertices that are not collinear
|
||||
int i = 0;
|
||||
int j = 1;
|
||||
int k = 2;
|
||||
if (polygon_vertex_count > 3) { // case where we'd have the possibility of noncollinearity
|
||||
bool b = determine_three_noncollinear_vertices(i, j, k, polygon_vertices, polygon_plane_normal,
|
||||
polygon_normal_max_comp);
|
||||
|
||||
if (!b) {
|
||||
return '0'; // all polygon points are collinear
|
||||
}
|
||||
}
|
||||
|
||||
double qRes = orient3d(polygon_vertices[i], polygon_vertices[j], polygon_vertices[k], q);
|
||||
double rRes = orient3d(polygon_vertices[i], polygon_vertices[j], polygon_vertices[k], r);
|
||||
|
||||
if (qRes == double(0.0) && rRes == double(0.0)) {
|
||||
// both points used to define line lie on plane therefore we have an in-plane intersection
|
||||
// or the polygon is a degenerate triangle
|
||||
return 'p';
|
||||
} else {
|
||||
if ((rRes < double(0.0) && qRes < double(0.0)) || (rRes > double(0.0) && qRes > double(0.0))) { // both points used to define line lie on same side of plane
|
||||
// check if line is parallel to plane
|
||||
// const double num = polygon_plane_d_coeff - dot_product(q, polygon_plane_normal);
|
||||
const vec3 rq = (r - q);
|
||||
const double denom = dot_product(rq, polygon_plane_normal);
|
||||
|
||||
if (denom == double(0.0) /* Segment is parallel to plane.*/) {
|
||||
// MCUT_ASSERT(num != 0.0); // implies 'q' is on plane (see: "compute_segment_plane_intersection(...)")
|
||||
// but we have already established that q and r are on same side.
|
||||
return '0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// q and r are on difference sides of the plane, therefore we have an intersection
|
||||
return '1';
|
||||
}
|
||||
|
||||
// Compute the intersection point between a line (not a segment) and a plane defined by a polygon.
|
||||
//
|
||||
// Parameters:
|
||||
// 'p' : output intersection point (computed if line does indeed intersect the plane)
|
||||
// 'q' : first point defining your line
|
||||
// 'r' : second point defining your line
|
||||
// 'polygon_vertices' : the vertices of the polygon defineing the plane (assumed to not be degenerate)
|
||||
// 'polygon_vertex_count' : number of olygon vertices
|
||||
// 'polygon_normal_max_comp' : largest component of polygon normal.
|
||||
// 'polygon_plane_normal' : normal of the given polygon
|
||||
// 'polygon_plane_d_coeff' : the distance coefficient of the plane equation corresponding to the polygon's plane
|
||||
//
|
||||
// Return values:
|
||||
// '0': line is parallel to plane (or polygon is degenerate ... within available precision)
|
||||
// '1': an intersection exists.
|
||||
// 'p': q and r lie in the plane (technically they are parallel to the plane too but we need to report this because it
|
||||
// violates GP).
|
||||
char compute_line_plane_intersection(vec3& p, // intersection point
|
||||
const vec3& q, const vec3& r,
|
||||
const std::vector<vec3>& polygon_vertices, const int polygon_normal_max_comp,
|
||||
const vec3& polygon_plane_normal,
|
||||
const double& polygon_plane_d_coeff)
|
||||
{
|
||||
|
||||
const int polygon_vertex_count = (int)polygon_vertices.size();
|
||||
// ... any three vertices that are not collinear
|
||||
int i = 0;
|
||||
int j = 1;
|
||||
int k = 2;
|
||||
if (polygon_vertex_count > 3) { // case where we'd have the possibility of noncollinearity
|
||||
bool b = determine_three_noncollinear_vertices(i, j, k, polygon_vertices, polygon_plane_normal,
|
||||
polygon_normal_max_comp);
|
||||
|
||||
if (!b) {
|
||||
return '0'; // all polygon points are collinear
|
||||
}
|
||||
}
|
||||
|
||||
double qRes = orient3d(polygon_vertices[i], polygon_vertices[j], polygon_vertices[k], q);
|
||||
double rRes = orient3d(polygon_vertices[i], polygon_vertices[j], polygon_vertices[k], r);
|
||||
|
||||
if (qRes == double(0.) && rRes == double(0.)) {
|
||||
return 'p'; // both points used to define line lie on plane therefore we have an in-plane intersection
|
||||
} else {
|
||||
|
||||
const double num = polygon_plane_d_coeff - dot_product(q, polygon_plane_normal);
|
||||
const vec3 rq = (r - q);
|
||||
const double denom = dot_product(rq, polygon_plane_normal);
|
||||
|
||||
if ((rRes < double(0.) && qRes < double(0.)) || (rRes > double(0.) && qRes > double(0.))) { // both q an r are on same side of plane
|
||||
if (denom == double(0.) /* line is parallel to plane.*/) {
|
||||
return '0';
|
||||
}
|
||||
}
|
||||
|
||||
// q and r are on difference sides of the plane, therefore we have an intersection
|
||||
|
||||
// compute the intersection point
|
||||
const double t = num / denom;
|
||||
|
||||
for (int it = 0; it < 3; ++it) {
|
||||
p[it] = q[it] + t * (r[it] - q[it]);
|
||||
}
|
||||
|
||||
return '1';
|
||||
}
|
||||
}
|
||||
|
||||
// Count the number ray crossings to determine if a point 'q' lies inside or outside a given polygon.
|
||||
//
|
||||
// Return values:
|
||||
// 'i': q is strictly interior
|
||||
// 'o': q is strictly exterior (outside).
|
||||
// 'e': q is on an edge, but not an endpoint.
|
||||
// 'v': q is a vertex.
|
||||
char compute_point_in_polygon_test(const vec2& q, const std::vector<vec2>& polygon_vertices)
|
||||
{
|
||||
const int polygon_vertex_count = (int)polygon_vertices.size();
|
||||
|
||||
#if 0 // Algorithm 1 in :
|
||||
// https://pdf.sciencedirectassets.com/271512/1-s2.0-S0925772100X00545/1-s2.0-S0925772101000128/main.pdf?X-Amz-Security-Token=IQoJb3JpZ2luX2VjEAEaCXVzLWVhc3QtMSJHMEUCIBr6Fu%2F%2FtscErn%2Fl4pn2UGNA45sAw9vggQscK7Tnl0ssAiEAzfnyy4B4%2BXkZp8xcEk7utDBrxgmGyH7pyqk0efKOUEoq%2BgMIKhAEGgwwNTkwMDM1NDY4NjUiDHQT4kOfk4%2B6kBB0xCrXAzd8SWlnELJbM5l93HSvv4nUgtO85%2FGyx5%2BOoHmYoUuVwJjCXChmLJmlz%2BxYUQE%2Fr8vQa2hPlUEPfiTVGgoHaK8NkSMP6LRs%2F3WjyZ9OxzHbqSwZixNceW34OAkq0E1QgYLdGVjpPKxNK1haXDfBTMN6bF2IOU9dKi9wTv3uTlep0kHDa1BNNl6M6yZk5QlF2bPF9XmNjjZCpFQLhr%2BPoHo%2Bx4xy39aH8hCkkTqGdy2KrKGN6lv0%2FduIaItyZfqalYS%2BwW6cll2F5G11g0tSu7yKu6mug94LUTzsRmzD0UhzeGl2WV6Ev2qhw26mwFEKgnTMqGst8XAHjFjjAQyMzXNHCQqNBRIevHIzVWuUY4QZMylSRsodo0dfwwCFhzl0%2BJA1ZXb0%2BoyB8c11meQBO8FpMSshngNcbiAYUtIOFcHNCTCUMk0JPOZ%2FxvANsopnivbrPARL71zU4PaTujg5jfC2zoO6ZDUL8E6Vn%2BNtfb%2BuQV7DwtIH51Bv%2F%2F1m6h5mjbpRiGYcH%2F5SDD%2Fk%2BpHfKRQzKu7jJc%2B0XO0bQvoLSrAte0Qk10PwOvDl5jMIMdmxTBDDiDGErRykYxMQhq5EwjyiWPXzM3ll9uK59Vy0bAEj5Qemj5by1jCDht6IBjqlAV4okAPQO5wWdWojCYeKvluKfXCvudrUxrLhsxb7%2BTZNMODTG%2Fn%2Fbw875Yr6fOQ42u40pOsnPB%2FTP3cWwjiB%2BEHzDqN8AhCVQyoedw7QrU3OBWlSl6lB%2BGLAVqrhcizgFUiM2nj3HaVP2m7S%2FXqpv%2FoWlEXt4gR8iI9XsIlh6L6SBE22FqbsU5ewCxXaqip19VXhAGnlvjTihXUg6yZGWhExHj%2BKcA%3D%3D&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20210814T103958Z&X-Amz-SignedHeaders=host&X-Amz-Expires=300&X-Amz-Credential=ASIAQ3PHCVTY3PPQSW2L%2F20210814%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=94403dce5c12ede9507e9612c000db5772607e59a2134d30d4e5b44212056dc7&hash=cada083b165f9786e6042e21d3d22147ec08b1e2c8fa2572ceeb2445cb5e730a&host=68042c943591013ac2b2430a89b270f6af2c76d8dfd086a07176afe7c76c2c61&pii=S0925772101000128&tid=spdf-f9e7c4b7-808d-4a8e-a474-6430ff687798&sid=8dddff5b32fff2499908bf6501965aec3d0fgxrqb&type=client
|
||||
|
||||
const double zero(0.0);
|
||||
int i = 0;
|
||||
int k = 0;
|
||||
|
||||
double f = zero;
|
||||
double u1 = 0.0;
|
||||
double v1 = 0.0;
|
||||
double u2 = 0.0;
|
||||
double v2 = 0.0;
|
||||
const int n = polygon_vertex_count;
|
||||
for (i = 0; i < n; ++i)
|
||||
{
|
||||
v1 = polygon_vertices[i].y() - q.y();
|
||||
v2 = polygon_vertices[(i + 1) % n].y() - q.y();
|
||||
|
||||
if ((v1 < zero && v2 < zero) || (v1 > zero && v2 > zero))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
u1 = polygon_vertices[i].x() - q.x();
|
||||
u2 = polygon_vertices[(i + 1) % n].x() - q.x();
|
||||
|
||||
if (v2 > zero && v1 <= zero)
|
||||
{
|
||||
f = u1 * v2 - u2 * v1;
|
||||
if (f > zero)
|
||||
{
|
||||
k = k + 1;
|
||||
}
|
||||
else if (f == zero)
|
||||
{
|
||||
return 'e'; //-1; // boundary
|
||||
}
|
||||
}
|
||||
else if (v1 > zero && v2 <= zero)
|
||||
{
|
||||
f = u1 * v2 - u2 * v1;
|
||||
if (f < zero)
|
||||
{
|
||||
k = k + 1;
|
||||
}
|
||||
else if (f == zero)
|
||||
{
|
||||
return 'e'; //-1; // boundary
|
||||
}
|
||||
}
|
||||
else if (v2 == zero && v1 < zero)
|
||||
{
|
||||
f = u1 * v2 - u2 * v1;
|
||||
if (f == zero)
|
||||
{
|
||||
return 'e'; //-1; // // boundary
|
||||
}
|
||||
}
|
||||
else if (v1 == zero && v2 < zero)
|
||||
{
|
||||
f = u1 * v2 - u2 * v1;
|
||||
if (f == zero)
|
||||
{
|
||||
return 'e'; //-1; // boundary
|
||||
}
|
||||
}
|
||||
else if (v1 == zero && v2 == zero)
|
||||
{
|
||||
if (u2 <= zero && u1 >= zero)
|
||||
{
|
||||
return 'e'; //-1; // boundary
|
||||
}
|
||||
else if (u1 <= zero && u2 >= zero)
|
||||
{
|
||||
return 'e'; //-1; // boundary
|
||||
}
|
||||
}
|
||||
}
|
||||
if (k % 2 == 0)
|
||||
{
|
||||
return 'o'; //0; // outside
|
||||
}
|
||||
else
|
||||
{
|
||||
return 'i'; //1; // inside
|
||||
}
|
||||
#else // http://www.science.smith.edu/~jorourke/books/compgeom.html
|
||||
|
||||
std::vector<vec2> vertices(polygon_vertex_count, vec2());
|
||||
// Shift so that q is the origin. Note this destroys the polygon.
|
||||
// This is done for pedagogical clarity.
|
||||
for (int i = 0; i < polygon_vertex_count; i++) {
|
||||
for (int d = 0; d < 2; d++) {
|
||||
const double& a = polygon_vertices[i][d];
|
||||
const double& b = q[d];
|
||||
double& c = vertices[i][d];
|
||||
c = a - b;
|
||||
}
|
||||
}
|
||||
|
||||
int Rcross = 0; /* number of right edge/ray crossings */
|
||||
int Lcross = 0; /* number ofleft edge/ray crossings */
|
||||
|
||||
/* For each edge e = (i<>lj), see if crosses ray. */
|
||||
for (int i = 0; i < polygon_vertex_count; i++) {
|
||||
|
||||
/* First check if q = (0, 0) is a vertex. */
|
||||
if (vertices[i].x() == double(0.) && vertices[i].y() == double(0.)) {
|
||||
return 'v';
|
||||
}
|
||||
|
||||
int il = (i + polygon_vertex_count - 1) % polygon_vertex_count;
|
||||
|
||||
// Check if e straddles x axis, with bias above/below.
|
||||
|
||||
// Rstrad is TRUE iff one endpoint of e is strictly above the x axis and the other is not (i.e., the other is on
|
||||
// or below)
|
||||
bool Rstrad = (vertices[i].y() > double(0.)) != (vertices[il].y() > double(0.));
|
||||
bool Lstrad = (vertices[i].y() < double(0.)) != (vertices[il].y() < double(0.));
|
||||
|
||||
if (Rstrad || Lstrad) {
|
||||
/* Compute intersection of e with x axis. */
|
||||
|
||||
// The computation of x is needed whenever either of these straddle variables is TRUE, which
|
||||
// only excludes edges passing through q = (0, 0) (and incidentally protects against division by 0).
|
||||
double x = (vertices[i].x() * vertices[il].y() - vertices[il].x() * vertices[i].y()) / (vertices[il].y() - vertices[i].y());
|
||||
if (Rstrad && x > double(0.)) {
|
||||
Rcross++;
|
||||
}
|
||||
if (Lstrad && x < double(0.)) {
|
||||
Lcross++;
|
||||
}
|
||||
} /* end straddle computation*/
|
||||
} // end for
|
||||
|
||||
/* q on an edge if L/Rcross counts are not the same parity.*/
|
||||
if ((Rcross % 2) != (Lcross % 2)) {
|
||||
return 'e';
|
||||
}
|
||||
|
||||
/* q inside iff an odd number of crossings. */
|
||||
if ((Rcross % 2) == 1) {
|
||||
return 'i';
|
||||
} else {
|
||||
return 'o';
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// given a normal vector (not necessarily normalized) and its largest component, calculate
|
||||
// a matrix P that will project any 3D vertex to 2D by removing the 3D component that
|
||||
// corresponds to the largest component of the normal..
|
||||
// https://math.stackexchange.com/questions/180418/calculate-rotation-matrix-to-align-vector-a-to-vector-b-in-3d/2672702#2672702
|
||||
matrix_t<double> calculate_projection_matrix(const vec3& polygon_normal,
|
||||
const int polygon_normal_largest_component)
|
||||
{
|
||||
MCUT_ASSERT(squared_length(polygon_normal) > double(0.0));
|
||||
MCUT_ASSERT(polygon_normal_largest_component >= 0);
|
||||
MCUT_ASSERT(polygon_normal_largest_component <= 2);
|
||||
|
||||
// unit length normal vector of polygon
|
||||
const vec3 a = normalize(polygon_normal);
|
||||
// unit length basis vector corresponding to the largest component of the normal vector
|
||||
const vec3 b = [&]() {
|
||||
vec3 x(double(0.0));
|
||||
const sign_t s = sign(polygon_normal[polygon_normal_largest_component]);
|
||||
MCUT_ASSERT(s != sign_t::ZERO); // implies that the normal vector has a magnitude of zero
|
||||
// The largest component of the normal is the one we will "remove"
|
||||
// NOTE: we multiple by the sign here to ensure that "a_plus_b" below is not zero when a == b
|
||||
x[polygon_normal_largest_component] = double((1.0) * static_cast<long double>(s));
|
||||
return x;
|
||||
}();
|
||||
|
||||
matrix_t<double> I(3, 3); // 3x3 identity
|
||||
I(0, 0) = 1.0;
|
||||
I(1, 1) = 1.0;
|
||||
I(2, 2) = 1.0;
|
||||
|
||||
matrix_t<double> R = I;
|
||||
|
||||
// NOTE: While this will map vectors a to b, it can add a lot of unnecessary "twist".
|
||||
// For example, if a=b=e_{z} this formula will produce a 180-degree rotation about the z-axis rather
|
||||
// than the identity one might expect.
|
||||
if ((a[0] != b[0]) || (a[1] != b[1]) || (a[2] != b[2])) // a != b
|
||||
{
|
||||
const vec3 a_plus_b = a + b;
|
||||
const double a_dot_b = dot_product(a, b);
|
||||
|
||||
// this will never be zero because we set 'b' as the canonical basis vector
|
||||
// that has the largest projection onto the normal
|
||||
MCUT_ASSERT(a_dot_b != double(0.0));
|
||||
|
||||
const matrix_t<double> outer = outer_product(a_plus_b, a_plus_b);
|
||||
|
||||
// compute the 3x3 rotation matrix R to orient the polygon into the canonical axes "i" and "j",
|
||||
// where "i" and "j" != "polygon_normal_largest_component"
|
||||
R = ((outer / a_dot_b) * 2.0) - I; // rotation
|
||||
}
|
||||
|
||||
// compute the 2x3 selector matrix K to select the polygon-vertex components that correspond
|
||||
// to canonical axes "i" and "j".
|
||||
matrix_t<double> K = matrix_t<double>(2, 3);
|
||||
|
||||
if (polygon_normal_largest_component == 0) // project by removing x-component
|
||||
{
|
||||
// 1st row
|
||||
K(0, 0) = 0.0; // col 0
|
||||
K(0, 1) = 1.0; // col 1
|
||||
K(0, 2) = 0.0; // col 2
|
||||
// 2nd row
|
||||
K(1, 0) = 0.0; // col 0
|
||||
K(1, 1) = 0.0; // col 1
|
||||
K(1, 2) = 1.0; // col 2
|
||||
} else if (polygon_normal_largest_component == 1) // project by removing y-component
|
||||
{
|
||||
// 1st row
|
||||
K(0, 0) = 1.0; // col 0
|
||||
K(0, 1) = 0.0; // col 1
|
||||
K(0, 2) = 0.0; // col 2
|
||||
// 2nd row
|
||||
K(1, 0) = 0.0; // col 0
|
||||
K(1, 1) = 0.0; // col 1
|
||||
K(1, 2) = 1.0; // col 2
|
||||
} else if (polygon_normal_largest_component == 2) // project by removing z-component
|
||||
{
|
||||
// 1st row
|
||||
K(0, 0) = 1.0; // col 0
|
||||
K(0, 1) = 0.0; // col 1
|
||||
K(0, 2) = 0.0; // col 2
|
||||
// 2nd row
|
||||
K(1, 0) = 0.0; // col 0
|
||||
K(1, 1) = 1.0; // col 1
|
||||
K(1, 2) = 0.0; // col 2
|
||||
}
|
||||
|
||||
return K * R;
|
||||
}
|
||||
|
||||
// https://answers.unity.com/questions/1522620/converting-a-3d-polygon-into-a-2d-polygon.html
|
||||
void project_to_2d(std::vector<vec2>& out, const std::vector<vec3>& polygon_vertices, const vec3& polygon_normal)
|
||||
{
|
||||
const uint32_t N = polygon_vertices.size();
|
||||
out.resize(N);
|
||||
|
||||
const vec3 normal = normalize(polygon_normal);
|
||||
|
||||
// first unit vector on plane (rotation by 90 degrees)
|
||||
vec3 u(-normal.y(), normal.x(), normal.z());
|
||||
vec3 v = normalize(cross_product(u, normal));
|
||||
|
||||
for(uint32_t i =0; i < N; ++i)
|
||||
{
|
||||
const vec3 point = polygon_vertices[i];
|
||||
const vec2 projected(
|
||||
dot_product(point, u),
|
||||
dot_product(point, v)
|
||||
);
|
||||
|
||||
out[i] = projected;
|
||||
}
|
||||
}
|
||||
|
||||
void project_to_2d(std::vector<vec2>& out, const std::vector<vec3>& polygon_vertices,
|
||||
const vec3& polygon_normal, const int polygon_normal_largest_component)
|
||||
{
|
||||
const int polygon_vertex_count = (int)polygon_vertices.size();
|
||||
out.clear();
|
||||
out.resize(polygon_vertex_count);
|
||||
|
||||
#if 1
|
||||
// 3x3 matrix for projecting a point to 2D
|
||||
matrix_t<double> P = calculate_projection_matrix(polygon_normal, polygon_normal_largest_component);
|
||||
for (int i = 0; i < polygon_vertex_count; ++i) { // for each vertex
|
||||
const vec3& x = polygon_vertices[i];
|
||||
out[i] = P * x; // vertex in xz plane
|
||||
}
|
||||
#else // This code is not reliable because it shadow-projects a polygons which can skew computations
|
||||
for (int i = 0; i < polygon_vertex_count; ++i) { // for each vertex
|
||||
vec2& Tp = out[i];
|
||||
int k = 0;
|
||||
for (int j = 0; j < 3; j++) { // for each component
|
||||
if (j != polygon_plane_normal_largest_component) { /* skip largest coordinate */
|
||||
|
||||
Tp[k] = polygon_vertices[i][j];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// TODO: update this function to use "project_to_2d" for projection step
|
||||
char compute_point_in_polygon_test(const vec3& p, const std::vector<vec3>& polygon_vertices,
|
||||
const vec3& polygon_normal, const int polygon_normal_largest_component)
|
||||
{
|
||||
const int polygon_vertex_count = (int)polygon_vertices.size();
|
||||
/* Project out coordinate m in both p and the triangular face */
|
||||
vec2 pp; /*projected p */
|
||||
#if 0
|
||||
int k = 0;
|
||||
|
||||
for (int j = 0; j < 3; j++)
|
||||
{ // for each component
|
||||
if (j != polygon_plane_normal_largest_component)
|
||||
{ /* skip largest coordinate */
|
||||
pp[k] = p[j];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const matrix_t<double> P = calculate_projection_matrix(polygon_normal, polygon_normal_largest_component);
|
||||
|
||||
pp = P * p;
|
||||
|
||||
std::vector<vec2> polygon_vertices2d(polygon_vertex_count, vec2());
|
||||
|
||||
for (int i = 0; i < polygon_vertex_count; ++i) { // for each vertex
|
||||
const vec3& x = polygon_vertices[i];
|
||||
polygon_vertices2d[i] = P * x; // vertex in xz plane
|
||||
}
|
||||
|
||||
#if 0
|
||||
for (int i = 0; i < polygon_vertex_count; ++i)
|
||||
{ // for each vertex
|
||||
vec2 &Tp = polygon_vertices2d[i];
|
||||
k = 0;
|
||||
for (int j = 0; j < 3; j++)
|
||||
{ // for each component
|
||||
if (j != polygon_plane_normal_largest_component)
|
||||
{ /* skip largest coordinate */
|
||||
|
||||
Tp[k] = polygon_vertices[i][j];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return compute_point_in_polygon_test(pp, polygon_vertices2d);
|
||||
}
|
||||
|
||||
inline bool Between(const vec2& a, const vec2& b, const vec2& c)
|
||||
{
|
||||
vec2 ba, ca;
|
||||
/* If ab not vertical check betweenness on x; else on y. */
|
||||
if (a[0] != b[0])
|
||||
return ((a[0] <= c[0]) && (c[0] <= b[0])) || //
|
||||
((a[0] >= c[0]) && (c[0] >= b[0]));
|
||||
else
|
||||
return ((a[1] <= c[1]) && (c[1] <= b[1])) || //
|
||||
((a[1] >= c[1]) && (c[1] >= b[1]));
|
||||
}
|
||||
|
||||
bool coplaner(const vec3& pa, const vec3& pb, const vec3& pc,
|
||||
const vec3& pd)
|
||||
{
|
||||
const double val = orient3d(pa, pb, pc, pd);
|
||||
// typedef std::numeric_limits<double> dbl;
|
||||
|
||||
// double d = 3.14159265358979;
|
||||
// std::cout.precision(dbl::max_digits10);
|
||||
// std::cout << "value=" << (double)val << std::endl;
|
||||
|
||||
// NOTE: thresholds are chosen based on benchmark meshes that are used for testing.
|
||||
// It is extremely difficult to get this right because of intermediate conversions
|
||||
// between exact and fixed precision representations during cutting.
|
||||
// Thus, general advise is for user to ensure that the input polygons are really
|
||||
// co-planer. It might be possible for MCUT to help here (see eps used during poly
|
||||
// partitioning).
|
||||
return absolute_value(val) <= double(4e-7);
|
||||
}
|
||||
|
||||
bool collinear(const vec2& a, const vec2& b, const vec2& c, double& predResult)
|
||||
{
|
||||
predResult = orient2d(a, b, c);
|
||||
return predResult == double(0.);
|
||||
}
|
||||
|
||||
bool collinear(const vec2& a, const vec2& b, const vec2& c)
|
||||
{
|
||||
return orient2d(a, b, c) == double(0.);
|
||||
}
|
||||
|
||||
char Parallellnt(const vec2& a, const vec2& b, const vec2& c, const vec2& d, vec2& p)
|
||||
{
|
||||
if (!collinear(a, b, c)) {
|
||||
return '0';
|
||||
}
|
||||
|
||||
if (Between(a, b, c)) {
|
||||
p = c;
|
||||
return 'e';
|
||||
}
|
||||
|
||||
if (Between(a, b, d)) {
|
||||
p = d;
|
||||
return 'e';
|
||||
}
|
||||
|
||||
if (Between(c, d, a)) {
|
||||
p = a;
|
||||
return 'e';
|
||||
}
|
||||
|
||||
if (Between(c, d, b)) {
|
||||
p = b;
|
||||
return 'e';
|
||||
}
|
||||
|
||||
return '0';
|
||||
}
|
||||
|
||||
char compute_segment_intersection(
|
||||
const vec2& a, const vec2& b, const vec2& c,
|
||||
const vec2& d, vec2& p, double& s, double& t)
|
||||
{
|
||||
// double s, t; /* The two parameters of the parametric eqns. */
|
||||
double num, denom; /* Numerator and denominator of equations. */
|
||||
char code = '?'; /* Return char characterizing intersection.*/
|
||||
|
||||
denom = a[0] * (d[1] - c[1]) + //
|
||||
b[0] * (c[1] - d[1]) + //
|
||||
d[0] * (b[1] - a[1]) + //
|
||||
c[0] * (a[1] - b[1]);
|
||||
|
||||
/* If denom is zero, then segments are parallel: handle separately. */
|
||||
if (denom == double(0.0)) {
|
||||
return Parallellnt(a, b, c, d, p);
|
||||
}
|
||||
|
||||
num = a[0] * (d[1] - c[1]) + //
|
||||
c[0] * (a[1] - d[1]) + //
|
||||
d[0] * (c[1] - a[1]);
|
||||
|
||||
if ((num == double(0.0)) || (num == denom)) {
|
||||
code = 'v';
|
||||
}
|
||||
|
||||
s = num / denom;
|
||||
|
||||
num = -(a[0] * (c[1] - b[1]) + //
|
||||
b[0] * (a[1] - c[1]) + //
|
||||
c[0] * (b[1] - a[1]));
|
||||
|
||||
if ((num == double(0.0)) || (num == denom)) {
|
||||
code = 'v';
|
||||
}
|
||||
|
||||
t = num / denom;
|
||||
|
||||
if ((double(0.0) < s) && (s < double(1.0)) && (double(0.0) < t) && (t < double(1.0))) {
|
||||
code = '1';
|
||||
} else if ((double(0.0) > s) || (s > double(1.0)) || (double(0.0) > t) || (t > double(1.0))) {
|
||||
code = '0';
|
||||
}
|
||||
|
||||
p[0] = a[0] + s * (b[0] - a[0]);
|
||||
p[1] = a[1] + s * (b[1] - a[1]);
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
inline bool point_in_bounding_box(const vec2& point, const bounding_box_t<vec2>& bbox)
|
||||
{
|
||||
if ((point.x() < bbox.m_minimum.x() || point.x() > bbox.m_maximum.x()) || //
|
||||
(point.y() < bbox.m_minimum.y() || point.y() > bbox.m_maximum.y())) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool point_in_bounding_box(const vec3& point, const bounding_box_t<vec3>& bbox)
|
||||
{
|
||||
if ((point.x() < bbox.m_minimum.x() || point.x() > bbox.m_maximum.x()) || //
|
||||
(point.y() < bbox.m_minimum.y() || point.y() > bbox.m_maximum.y()) || //
|
||||
(point.z() < bbox.m_minimum.z() || point.z() > bbox.m_maximum.z())) { //
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
764
src/mcut/source/mcut.cpp
Normal file
764
src/mcut/source/mcut.cpp
Normal file
|
|
@ -0,0 +1,764 @@
|
|||
/**
|
||||
* Copyright (c) 2021-2022 Floyd M. Chitalu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* NOTE: This file is licensed under GPL-3.0-or-later (default).
|
||||
* A commercial license can be purchased from Floyd M. Chitalu.
|
||||
*
|
||||
* License details:
|
||||
*
|
||||
* (A) GNU General Public License ("GPL"); a copy of which you should have
|
||||
* recieved with this file.
|
||||
* - see also: <http://www.gnu.org/licenses/>
|
||||
* (B) Commercial license.
|
||||
* - email: floyd.m.chitalu@gmail.com
|
||||
*
|
||||
* The commercial license options is for users that wish to use MCUT in
|
||||
* their products for comercial purposes but do not wish to release their
|
||||
* software products under the GPL license.
|
||||
*
|
||||
* Author(s) : Floyd M. Chitalu
|
||||
*/
|
||||
|
||||
#include "mcut/mcut.h"
|
||||
|
||||
#include "mcut/internal/frontend.h"
|
||||
#include "mcut/internal/timer.h"
|
||||
#include "mcut/internal/utils.h"
|
||||
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
|
||||
#if defined(MCUT_BUILD_WINDOWS)
|
||||
#pragma warning(disable : 26812)
|
||||
#endif
|
||||
|
||||
MCAPI_ATTR McResult MCAPI_CALL mcCreateContext(McContext* pOutContext, McFlags contextFlags)
|
||||
{
|
||||
McResult return_value = McResult::MC_NO_ERROR;
|
||||
per_thread_api_log_str.clear();
|
||||
|
||||
if (pOutContext == nullptr) {
|
||||
per_thread_api_log_str = "context ptr undef (NULL)";
|
||||
return_value = McResult::MC_INVALID_VALUE;
|
||||
} else {
|
||||
try {
|
||||
// no helper threads
|
||||
// only manager threads (2 managers if context is created with MC_OUT_OF_ORDER_EXEC_MODE_ENABLE, otherwise 1 manager)
|
||||
create_context_impl(pOutContext, contextFlags, 0);
|
||||
}
|
||||
CATCH_POSSIBLE_EXCEPTIONS(per_thread_api_log_str);
|
||||
}
|
||||
|
||||
if (return_value != McResult::MC_NO_ERROR) {
|
||||
std::fprintf(stderr, "%s(...) -> %s\n", __FUNCTION__, per_thread_api_log_str.c_str());
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
MCAPI_ATTR McResult MCAPI_CALL mcCreateContextWithHelpers(McContext* pOutContext, McFlags contextFlags, uint32_t helperThreadCount)
|
||||
{
|
||||
McResult return_value = McResult::MC_NO_ERROR;
|
||||
per_thread_api_log_str.clear();
|
||||
|
||||
if (pOutContext == nullptr) {
|
||||
per_thread_api_log_str = "context ptr undef (NULL)";
|
||||
return_value = McResult::MC_INVALID_VALUE;
|
||||
} else {
|
||||
try {
|
||||
create_context_impl(pOutContext, contextFlags, helperThreadCount);
|
||||
}
|
||||
CATCH_POSSIBLE_EXCEPTIONS(per_thread_api_log_str);
|
||||
}
|
||||
|
||||
if (return_value != McResult::MC_NO_ERROR) {
|
||||
std::fprintf(stderr, "%s(...) -> %s\n", __FUNCTION__, per_thread_api_log_str.c_str());
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
MCAPI_ATTR McResult MCAPI_CALL mcDebugMessageCallback(McContext pContext, pfn_mcDebugOutput_CALLBACK cb, const McVoid* userParam)
|
||||
{
|
||||
McResult return_value = McResult::MC_NO_ERROR;
|
||||
per_thread_api_log_str.clear();
|
||||
|
||||
if (pContext == nullptr) {
|
||||
per_thread_api_log_str = "context ptr (param0) undef (NULL)";
|
||||
} else if (cb == nullptr) {
|
||||
per_thread_api_log_str = "callback function ptr (param1) undef (NULL)";
|
||||
} else {
|
||||
try {
|
||||
debug_message_callback_impl(pContext, cb, userParam);
|
||||
}
|
||||
CATCH_POSSIBLE_EXCEPTIONS(per_thread_api_log_str);
|
||||
}
|
||||
|
||||
if (!per_thread_api_log_str.empty()) {
|
||||
std::fprintf(stderr, "%s(...) -> %s\n", __FUNCTION__, per_thread_api_log_str.c_str());
|
||||
|
||||
if (return_value == McResult::MC_NO_ERROR) // i.e. problem with basic local parameter checks
|
||||
{
|
||||
return_value = McResult::MC_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
MCAPI_ATTR McResult MCAPI_CALL mcGetDebugMessageLog(
|
||||
McContext context,
|
||||
McUint32 count, McSize bufSize,
|
||||
McDebugSource* sources, McDebugType* types, McDebugSeverity* severities,
|
||||
McSize* lengths, McChar* messageLog, McUint32* numFetched)
|
||||
{
|
||||
McResult return_value = McResult::MC_NO_ERROR;
|
||||
per_thread_api_log_str.clear();
|
||||
|
||||
if (context == nullptr) {
|
||||
per_thread_api_log_str = "context ptr (param0) undef (NULL)";
|
||||
} else if (
|
||||
count == 0) {
|
||||
per_thread_api_log_str = "count must be > 0";
|
||||
} else if (bufSize == 0) {
|
||||
per_thread_api_log_str = "bufSize must be > 0";
|
||||
} else if (numFetched == nullptr) {
|
||||
per_thread_api_log_str = "numFetched undef (NULL)";
|
||||
} else {
|
||||
try {
|
||||
get_debug_message_log_impl(context,
|
||||
count, bufSize,
|
||||
sources, types, severities,
|
||||
lengths, messageLog, *numFetched);
|
||||
}
|
||||
CATCH_POSSIBLE_EXCEPTIONS(per_thread_api_log_str);
|
||||
}
|
||||
|
||||
if (!per_thread_api_log_str.empty()) {
|
||||
std::fprintf(stderr, "%s(...) -> %s\n", __FUNCTION__, per_thread_api_log_str.c_str());
|
||||
if (return_value == McResult::MC_NO_ERROR) // i.e. problem with basic local parameter checks
|
||||
{
|
||||
return_value = McResult::MC_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
MCAPI_ATTR McResult MCAPI_CALL mcDebugMessageControl(McContext pContext, McDebugSource source, McDebugType type, McDebugSeverity severity, bool enabled)
|
||||
{
|
||||
McResult return_value = McResult::MC_NO_ERROR;
|
||||
per_thread_api_log_str.clear();
|
||||
|
||||
if (pContext == nullptr) {
|
||||
per_thread_api_log_str = "context ptr (param0) undef (NULL)";
|
||||
} else if (
|
||||
false == (source == McDebugSource::MC_DEBUG_SOURCE_ALL || //
|
||||
source == McDebugSource::MC_DEBUG_SOURCE_KERNEL || //
|
||||
source == McDebugSource::MC_DEBUG_SOURCE_ALL)) {
|
||||
per_thread_api_log_str = "debug source val (param1) invalid";
|
||||
} else if (
|
||||
false == (type == McDebugType::MC_DEBUG_TYPE_ALL || //
|
||||
type == McDebugType::MC_DEBUG_TYPE_DEPRECATED_BEHAVIOR || //
|
||||
type == McDebugType::MC_DEBUG_TYPE_ERROR || //
|
||||
type == McDebugType::MC_DEBUG_TYPE_OTHER)) {
|
||||
per_thread_api_log_str = "debug type val (param2) invalid";
|
||||
} else if (
|
||||
false == (severity == McDebugSeverity::MC_DEBUG_SEVERITY_HIGH || //
|
||||
severity == McDebugSeverity::MC_DEBUG_SEVERITY_MEDIUM || //
|
||||
severity == McDebugSeverity::MC_DEBUG_SEVERITY_LOW || //
|
||||
severity == McDebugSeverity::MC_DEBUG_SEVERITY_NOTIFICATION || //
|
||||
severity == McDebugSeverity::MC_DEBUG_SEVERITY_ALL)) {
|
||||
per_thread_api_log_str = "debug severity val (param3) invalid";
|
||||
} else {
|
||||
try {
|
||||
debug_message_control_impl(pContext, source, type, severity, enabled);
|
||||
}
|
||||
CATCH_POSSIBLE_EXCEPTIONS(per_thread_api_log_str);
|
||||
}
|
||||
|
||||
if (!per_thread_api_log_str.empty()) {
|
||||
std::fprintf(stderr, "%s(...) -> %s\n", __FUNCTION__, per_thread_api_log_str.c_str());
|
||||
if (return_value == McResult::MC_NO_ERROR) // i.e. problem with basic local parameter checks
|
||||
{
|
||||
return_value = McResult::MC_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
MCAPI_ATTR McResult MCAPI_CALL mcGetInfo(const McContext context, McFlags info, McSize bytes, McVoid* pMem, McSize* pNumBytes)
|
||||
{
|
||||
McResult return_value = McResult::MC_NO_ERROR;
|
||||
per_thread_api_log_str.clear();
|
||||
|
||||
if (context == nullptr) {
|
||||
per_thread_api_log_str = "context ptr (param0) undef (NULL)";
|
||||
} else if (bytes != 0 && pMem == nullptr) {
|
||||
per_thread_api_log_str = "invalid specification (param2 & param3)";
|
||||
} else if (false == (info == MC_CONTEXT_FLAGS || info == MC_MAX_DEBUG_MESSAGE_LENGTH)) // check all possible values
|
||||
{
|
||||
per_thread_api_log_str = "invalid info flag val (param1)";
|
||||
} else if ((info == MC_CONTEXT_FLAGS) && (pMem != nullptr && bytes != sizeof(McFlags))) {
|
||||
per_thread_api_log_str = "invalid byte size (param2)"; // leads to e.g. "out of bounds" memory access during memcpy
|
||||
} else {
|
||||
try {
|
||||
get_info_impl(context, info, bytes, pMem, pNumBytes);
|
||||
}
|
||||
CATCH_POSSIBLE_EXCEPTIONS(per_thread_api_log_str);
|
||||
}
|
||||
|
||||
if (!per_thread_api_log_str.empty()) {
|
||||
std::fprintf(stderr, "%s(...) -> %s\n", __FUNCTION__, per_thread_api_log_str.c_str());
|
||||
if (return_value == McResult::MC_NO_ERROR) // i.e. problem with basic local parameter checks
|
||||
{
|
||||
return_value = McResult::MC_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
MCAPI_ATTR McResult MCAPI_CALL mcCreateUserEvent(
|
||||
McEvent* event,
|
||||
McContext context)
|
||||
{
|
||||
McResult return_value = McResult::MC_NO_ERROR;
|
||||
per_thread_api_log_str.clear();
|
||||
|
||||
if (event == nullptr) {
|
||||
per_thread_api_log_str = "event ptr (param0) undef (NULL)";
|
||||
} else if (context == nullptr) {
|
||||
per_thread_api_log_str = "context handle undefined (NULL)";
|
||||
} else {
|
||||
try {
|
||||
create_user_event_impl(event, context);
|
||||
}
|
||||
CATCH_POSSIBLE_EXCEPTIONS(per_thread_api_log_str);
|
||||
}
|
||||
|
||||
if (!per_thread_api_log_str.empty()) {
|
||||
std::fprintf(stderr, "%s(...) -> %s\n", __FUNCTION__, per_thread_api_log_str.c_str());
|
||||
if (return_value == McResult::MC_NO_ERROR) // i.e. problem with basic local parameter checks
|
||||
{
|
||||
return_value = McResult::MC_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
MCAPI_ATTR McResult MCAPI_CALL mcSetUserEventStatus(
|
||||
McEvent event,
|
||||
McInt32 execution_status)
|
||||
{
|
||||
McResult return_value = McResult::MC_NO_ERROR;
|
||||
per_thread_api_log_str.clear();
|
||||
|
||||
if (event == nullptr) {
|
||||
per_thread_api_log_str = "event ptr (param0) undef (NULL)";
|
||||
} else {
|
||||
try {
|
||||
set_user_event_status_impl(event, execution_status);
|
||||
}
|
||||
CATCH_POSSIBLE_EXCEPTIONS(per_thread_api_log_str);
|
||||
}
|
||||
|
||||
if (!per_thread_api_log_str.empty()) {
|
||||
std::fprintf(stderr, "%s(...) -> %s\n", __FUNCTION__, per_thread_api_log_str.c_str());
|
||||
if (return_value == McResult::MC_NO_ERROR) // i.e. problem with basic local parameter checks
|
||||
{
|
||||
return_value = McResult::MC_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
MCAPI_ATTR McResult MCAPI_CALL mcGetEventInfo(const McEvent event, McFlags info, McSize bytes, McVoid* pMem, McSize* pNumBytes)
|
||||
{
|
||||
McResult return_value = McResult::MC_NO_ERROR;
|
||||
per_thread_api_log_str.clear();
|
||||
|
||||
if (event == nullptr) {
|
||||
per_thread_api_log_str = "context ptr (param0) undef (NULL)";
|
||||
} else if (bytes != 0 && pMem == nullptr) {
|
||||
per_thread_api_log_str = "invalid specification (param2 & param3)";
|
||||
} else if ((info == MC_EVENT_RUNTIME_EXECUTION_STATUS) && (pMem != nullptr && bytes != sizeof(McResult))) {
|
||||
per_thread_api_log_str = "invalid byte size (param2)"; // leads to e.g. "out of bounds" memory access during memcpy
|
||||
} else if ((info == MC_EVENT_COMMAND_EXECUTION_STATUS) && (pMem != nullptr && bytes != sizeof(McFlags))) {
|
||||
per_thread_api_log_str = "invalid byte size (param2)"; // leads to e.g. "out of bounds" memory access during memcpy
|
||||
} else if ((info == MC_EVENT_TIMESTAMP_SUBMIT || info == MC_EVENT_TIMESTAMP_START || info == MC_EVENT_TIMESTAMP_END) && (pMem != nullptr && bytes != sizeof(McSize))) {
|
||||
per_thread_api_log_str = "invalid byte size (param2)"; // leads to e.g. "out of bounds" memory access during memcpy
|
||||
} else {
|
||||
try {
|
||||
get_event_info_impl(event, info, bytes, pMem, pNumBytes);
|
||||
}
|
||||
CATCH_POSSIBLE_EXCEPTIONS(per_thread_api_log_str);
|
||||
}
|
||||
|
||||
if (!per_thread_api_log_str.empty()) {
|
||||
std::fprintf(stderr, "%s(...) -> %s\n", __FUNCTION__, per_thread_api_log_str.c_str());
|
||||
if (return_value == McResult::MC_NO_ERROR) // i.e. problem with basic local parameter checks
|
||||
{
|
||||
return_value = McResult::MC_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
MCAPI_ATTR McResult MCAPI_CALL mcWaitForEvents(
|
||||
uint32_t numEventsInWaitlist,
|
||||
const McEvent* pEventWaitList)
|
||||
{
|
||||
McResult return_value = McResult::MC_NO_ERROR;
|
||||
per_thread_api_log_str.clear();
|
||||
|
||||
if (pEventWaitList == nullptr && numEventsInWaitlist > 0) {
|
||||
per_thread_api_log_str = "invalid event waitlist ptr (NULL)";
|
||||
} else if (pEventWaitList != nullptr && numEventsInWaitlist == 0) {
|
||||
per_thread_api_log_str = "invalid event waitlist size (zero)";
|
||||
} else {
|
||||
try {
|
||||
McResult waitliststatus = MC_NO_ERROR;
|
||||
wait_for_events_impl(numEventsInWaitlist, pEventWaitList, waitliststatus);
|
||||
|
||||
if (waitliststatus != McResult::MC_NO_ERROR) {
|
||||
per_thread_api_log_str = "event in waitlist has an error";
|
||||
}
|
||||
}
|
||||
CATCH_POSSIBLE_EXCEPTIONS(per_thread_api_log_str);
|
||||
}
|
||||
|
||||
if (!per_thread_api_log_str.empty()) {
|
||||
|
||||
std::fprintf(stderr, "%s(...) -> %s\n", __FUNCTION__, per_thread_api_log_str.c_str());
|
||||
|
||||
if (return_value == McResult::MC_NO_ERROR) // i.e. problem with basic local parameter checks
|
||||
{
|
||||
return_value = McResult::MC_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
MCAPI_ATTR McResult MCAPI_CALL mcSetEventCallback(
|
||||
McEvent eventHandle,
|
||||
pfn_McEvent_CALLBACK eventCallback,
|
||||
McVoid* data)
|
||||
{
|
||||
McResult return_value = McResult::MC_NO_ERROR;
|
||||
per_thread_api_log_str.clear();
|
||||
|
||||
if (eventHandle == nullptr) {
|
||||
per_thread_api_log_str = "invalid event ptr (NULL)";
|
||||
}
|
||||
if (eventCallback == nullptr) {
|
||||
per_thread_api_log_str = "invalid event callback function ptr (NULL)";
|
||||
} else {
|
||||
try {
|
||||
set_event_callback_impl(eventHandle, eventCallback, data);
|
||||
}
|
||||
CATCH_POSSIBLE_EXCEPTIONS(per_thread_api_log_str);
|
||||
}
|
||||
|
||||
if (!per_thread_api_log_str.empty()) {
|
||||
|
||||
std::fprintf(stderr, "%s(...) -> %s\n", __FUNCTION__, per_thread_api_log_str.c_str());
|
||||
|
||||
if (return_value == McResult::MC_NO_ERROR) // i.e. problem with basic local parameter checks
|
||||
{
|
||||
return_value = McResult::MC_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
MCAPI_ATTR McResult MCAPI_CALL mcEnqueueDispatch(
|
||||
const McContext context,
|
||||
McFlags dispatchFlags,
|
||||
const McVoid* pSrcMeshVertices,
|
||||
const uint32_t* pSrcMeshFaceIndices,
|
||||
const uint32_t* pSrcMeshFaceSizes,
|
||||
uint32_t numSrcMeshVertices,
|
||||
uint32_t numSrcMeshFaces,
|
||||
const McVoid* pCutMeshVertices,
|
||||
const uint32_t* pCutMeshFaceIndices,
|
||||
const uint32_t* pCutMeshFaceSizes,
|
||||
uint32_t numCutMeshVertices,
|
||||
uint32_t numCutMeshFaces,
|
||||
uint32_t numEventsInWaitlist,
|
||||
const McEvent* pEventWaitList,
|
||||
McEvent* pEvent)
|
||||
{
|
||||
TIMESTACK_RESET(); // reset tracking vars
|
||||
|
||||
SCOPED_TIMER(__FUNCTION__);
|
||||
|
||||
McResult return_value = McResult::MC_NO_ERROR;
|
||||
per_thread_api_log_str.clear();
|
||||
|
||||
if (context == nullptr) {
|
||||
per_thread_api_log_str = "context ptr (param0) undef (NULL)";
|
||||
} else if (dispatchFlags == 0) {
|
||||
per_thread_api_log_str = "dispatch flags unspecified";
|
||||
} else if ((dispatchFlags & MC_DISPATCH_REQUIRE_THROUGH_CUTS) && //
|
||||
(dispatchFlags & MC_DISPATCH_FILTER_FRAGMENT_LOCATION_UNDEFINED)) {
|
||||
// The user states that she does not want a partial cut but yet also states that she
|
||||
// wants to keep fragments with partial cuts. These two options are mutually exclusive!
|
||||
per_thread_api_log_str = "use of mutually-exclusive flags: MC_DISPATCH_REQUIRE_THROUGH_CUTS & MC_DISPATCH_FILTER_FRAGMENT_LOCATION_UNDEFINED";
|
||||
} else if ((dispatchFlags & MC_DISPATCH_VERTEX_ARRAY_FLOAT) == 0 && (dispatchFlags & MC_DISPATCH_VERTEX_ARRAY_DOUBLE) == 0) {
|
||||
per_thread_api_log_str = "dispatch vertex aray type unspecified";
|
||||
} else if (pSrcMeshVertices == nullptr) {
|
||||
per_thread_api_log_str = "source-mesh vertex-position array ptr undef (NULL)";
|
||||
} else if (numSrcMeshVertices < 3) {
|
||||
per_thread_api_log_str = "invalid source-mesh vertex count";
|
||||
} else if (pSrcMeshFaceIndices == nullptr) {
|
||||
per_thread_api_log_str = "source-mesh face-index array ptr undef (NULL)";
|
||||
} /*else if (pSrcMeshFaceSizes == nullptr) {
|
||||
per_thread_api_log_str = "source-mesh face-size array ptr undef (NULL)";
|
||||
}*/
|
||||
else if (numSrcMeshFaces < 1) {
|
||||
per_thread_api_log_str = "invalid source-mesh vertex count";
|
||||
} else if (pCutMeshVertices == nullptr) {
|
||||
per_thread_api_log_str = "cut-mesh vertex-position array ptr undef (NULL)";
|
||||
} else if (numCutMeshVertices < 3) {
|
||||
per_thread_api_log_str = "invalid cut-mesh vertex count";
|
||||
} else if (pCutMeshFaceIndices == nullptr) {
|
||||
per_thread_api_log_str = "cut-mesh face-index array ptr undef (NULL)";
|
||||
} /*else if (pCutMeshFaceSizes == nullptr) {
|
||||
per_thread_api_log_str = "cut-mesh face-size array ptr undef (NULL)";
|
||||
} */
|
||||
else if (numCutMeshFaces < 1) {
|
||||
per_thread_api_log_str = "invalid cut-mesh vertex count";
|
||||
} else if (pEventWaitList == nullptr && numEventsInWaitlist > 0) {
|
||||
per_thread_api_log_str = "invalid event waitlist ptr (NULL)";
|
||||
} else if (pEventWaitList != nullptr && numEventsInWaitlist == 0) {
|
||||
per_thread_api_log_str = "invalid event waitlist size (zero)";
|
||||
} else if (pEventWaitList == nullptr && numEventsInWaitlist == 0 && pEvent == nullptr) {
|
||||
per_thread_api_log_str = "invalid event ptr (zero)";
|
||||
} else {
|
||||
try {
|
||||
dispatch_impl(
|
||||
context,
|
||||
dispatchFlags,
|
||||
pSrcMeshVertices,
|
||||
pSrcMeshFaceIndices,
|
||||
pSrcMeshFaceSizes,
|
||||
numSrcMeshVertices,
|
||||
numSrcMeshFaces,
|
||||
pCutMeshVertices,
|
||||
pCutMeshFaceIndices,
|
||||
pCutMeshFaceSizes,
|
||||
numCutMeshVertices,
|
||||
numCutMeshFaces,
|
||||
numEventsInWaitlist,
|
||||
pEventWaitList,
|
||||
pEvent);
|
||||
}
|
||||
CATCH_POSSIBLE_EXCEPTIONS(per_thread_api_log_str);
|
||||
}
|
||||
|
||||
if (!per_thread_api_log_str.empty()) {
|
||||
|
||||
std::fprintf(stderr, "%s(...) -> %s\n", __FUNCTION__, per_thread_api_log_str.c_str());
|
||||
|
||||
if (return_value == McResult::MC_NO_ERROR) // i.e. problem with basic local parameter checks
|
||||
{
|
||||
return_value = McResult::MC_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
MCAPI_ATTR McResult MCAPI_CALL mcDispatch(
|
||||
const McContext context,
|
||||
McFlags dispatchFlags,
|
||||
const McVoid* pSrcMeshVertices,
|
||||
const uint32_t* pSrcMeshFaceIndices,
|
||||
const uint32_t* pSrcMeshFaceSizes,
|
||||
uint32_t numSrcMeshVertices,
|
||||
uint32_t numSrcMeshFaces,
|
||||
const McVoid* pCutMeshVertices,
|
||||
const uint32_t* pCutMeshFaceIndices,
|
||||
const uint32_t* pCutMeshFaceSizes,
|
||||
uint32_t numCutMeshVertices,
|
||||
uint32_t numCutMeshFaces)
|
||||
{
|
||||
McEvent event = MC_NULL_HANDLE;
|
||||
|
||||
McResult return_value = mcEnqueueDispatch(
|
||||
context,
|
||||
dispatchFlags,
|
||||
pSrcMeshVertices,
|
||||
pSrcMeshFaceIndices,
|
||||
pSrcMeshFaceSizes,
|
||||
numSrcMeshVertices,
|
||||
numSrcMeshFaces,
|
||||
pCutMeshVertices,
|
||||
pCutMeshFaceIndices,
|
||||
pCutMeshFaceSizes,
|
||||
numCutMeshVertices,
|
||||
numCutMeshFaces,
|
||||
0,
|
||||
nullptr,
|
||||
&event);
|
||||
|
||||
if (return_value == MC_NO_ERROR) { // API parameter checks are fine
|
||||
if (event != MC_NULL_HANDLE) // event must exist to wait on and query
|
||||
{
|
||||
McResult waitliststatus = MC_NO_ERROR;
|
||||
|
||||
wait_for_events_impl(1, &event, waitliststatus); // block until event of mcEnqueueDispatch is completed!
|
||||
|
||||
if (waitliststatus != McResult::MC_NO_ERROR) {
|
||||
return_value = waitliststatus;
|
||||
}
|
||||
|
||||
release_events_impl(1, &event); // destroy
|
||||
}
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
MCAPI_ATTR McResult MCAPI_CALL mcEnqueueGetConnectedComponents(
|
||||
const McContext context,
|
||||
const McConnectedComponentType connectedComponentType,
|
||||
const uint32_t numEntries,
|
||||
McConnectedComponent* pConnComps,
|
||||
uint32_t* numConnComps,
|
||||
uint32_t numEventsInWaitlist,
|
||||
const McEvent* pEventWaitList,
|
||||
McEvent* pEvent)
|
||||
{
|
||||
McResult return_value = McResult::MC_NO_ERROR;
|
||||
per_thread_api_log_str.clear();
|
||||
|
||||
if (context == nullptr) {
|
||||
per_thread_api_log_str = "context ptr (param0) undef (NULL)";
|
||||
} else if (connectedComponentType == 0) {
|
||||
per_thread_api_log_str = "invalid type-parameter (param1) (0)";
|
||||
} else if (numConnComps == nullptr && pConnComps == nullptr) {
|
||||
per_thread_api_log_str = "output parameters undef (param3 & param4)";
|
||||
} else if (pEventWaitList == nullptr && numEventsInWaitlist > 0) {
|
||||
per_thread_api_log_str = "invalid event waitlist ptr (NULL)";
|
||||
} else if (pEventWaitList != nullptr && numEventsInWaitlist == 0) {
|
||||
per_thread_api_log_str = "invalid event waitlist size (zero)";
|
||||
} else if (pEventWaitList == nullptr && numEventsInWaitlist == 0 && pEvent == nullptr) {
|
||||
per_thread_api_log_str = "invalid event ptr (zero)";
|
||||
} else {
|
||||
try {
|
||||
|
||||
get_connected_components_impl(context, connectedComponentType, numEntries, pConnComps, numConnComps, numEventsInWaitlist, pEventWaitList, pEvent);
|
||||
}
|
||||
CATCH_POSSIBLE_EXCEPTIONS(per_thread_api_log_str);
|
||||
}
|
||||
|
||||
if (!per_thread_api_log_str.empty()) {
|
||||
|
||||
std::fprintf(stderr, "%s(...) -> %s\n", __FUNCTION__, per_thread_api_log_str.c_str());
|
||||
|
||||
if (return_value == McResult::MC_NO_ERROR) // i.e. problem with basic local parameter checks
|
||||
{
|
||||
return_value = McResult::MC_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
MCAPI_ATTR McResult MCAPI_CALL mcGetConnectedComponents(
|
||||
const McContext context,
|
||||
const McConnectedComponentType connectedComponentType,
|
||||
const uint32_t numEntries,
|
||||
McConnectedComponent* pConnComps,
|
||||
uint32_t* numConnComps)
|
||||
{
|
||||
McEvent event = MC_NULL_HANDLE;
|
||||
McResult return_value = mcEnqueueGetConnectedComponents(context, connectedComponentType, numEntries, pConnComps, numConnComps, 0, nullptr, &event);
|
||||
if (event != MC_NULL_HANDLE) // event must exist to wait on and query
|
||||
{
|
||||
McResult waitliststatus = MC_NO_ERROR;
|
||||
|
||||
wait_for_events_impl(1, &event, waitliststatus); // block until event of mcEnqueueDispatch is completed!
|
||||
|
||||
if (waitliststatus != McResult::MC_NO_ERROR) {
|
||||
return_value = waitliststatus;
|
||||
}
|
||||
release_events_impl(1, &event); // destroy
|
||||
}
|
||||
return return_value;
|
||||
}
|
||||
|
||||
MCAPI_ATTR McResult MCAPI_CALL mcEnqueueGetConnectedComponentData(
|
||||
const McContext context,
|
||||
const McConnectedComponent connCompId,
|
||||
McFlags queryFlags,
|
||||
McSize bytes,
|
||||
McVoid* pMem,
|
||||
McSize* pNumBytes,
|
||||
uint32_t numEventsInWaitlist,
|
||||
const McEvent* pEventWaitList,
|
||||
McEvent* pEvent)
|
||||
{
|
||||
McResult return_value = McResult::MC_NO_ERROR;
|
||||
per_thread_api_log_str.clear();
|
||||
|
||||
if (context == nullptr) {
|
||||
per_thread_api_log_str = "context ptr (param0) undef (NULL)";
|
||||
}
|
||||
if (connCompId == nullptr) {
|
||||
per_thread_api_log_str = "connected component ptr (param1) undef (NULL)";
|
||||
} else if (queryFlags == 0) {
|
||||
per_thread_api_log_str = "flags (param1) undef (0)";
|
||||
} else if (bytes != 0 && pMem == nullptr) {
|
||||
per_thread_api_log_str = "null parameter (param3 & param4)";
|
||||
} else if (pEventWaitList == nullptr && numEventsInWaitlist > 0) {
|
||||
per_thread_api_log_str = "invalid event waitlist ptr (NULL)";
|
||||
} else if (pEventWaitList != nullptr && numEventsInWaitlist == 0) {
|
||||
per_thread_api_log_str = "invalid event waitlist size (zero)";
|
||||
} else if (pEventWaitList == nullptr && numEventsInWaitlist == 0 && pEvent == nullptr) {
|
||||
per_thread_api_log_str = "invalid event ptr (zero)";
|
||||
} else {
|
||||
try {
|
||||
get_connected_component_data_impl(context, connCompId, queryFlags, bytes, pMem, pNumBytes, numEventsInWaitlist, pEventWaitList, pEvent);
|
||||
}
|
||||
CATCH_POSSIBLE_EXCEPTIONS(per_thread_api_log_str);
|
||||
}
|
||||
|
||||
if (!per_thread_api_log_str.empty()) {
|
||||
|
||||
std::fprintf(stderr, "%s(...) -> %s\n", __FUNCTION__, per_thread_api_log_str.c_str());
|
||||
|
||||
if (return_value == McResult::MC_NO_ERROR) // i.e. problem with basic local parameter checks
|
||||
{
|
||||
return_value = McResult::MC_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
MCAPI_ATTR McResult MCAPI_CALL mcGetConnectedComponentData(
|
||||
const McContext context,
|
||||
const McConnectedComponent connCompId,
|
||||
McFlags queryFlags,
|
||||
McSize bytes,
|
||||
McVoid* pMem,
|
||||
McSize* pNumBytes)
|
||||
{
|
||||
McEvent event = MC_NULL_HANDLE;
|
||||
McResult return_value = mcEnqueueGetConnectedComponentData(context, connCompId, queryFlags, bytes, pMem, pNumBytes, 0, nullptr, &event);
|
||||
if (event != MC_NULL_HANDLE) // event must exist to wait on and query
|
||||
{
|
||||
McResult waitliststatus = MC_NO_ERROR;
|
||||
|
||||
wait_for_events_impl(1, &event, waitliststatus); // block until event of mcEnqueueDispatch is completed!
|
||||
|
||||
if (waitliststatus != McResult::MC_NO_ERROR) {
|
||||
return_value = waitliststatus;
|
||||
}
|
||||
|
||||
release_events_impl(1, &event); // destroy
|
||||
}
|
||||
return return_value;
|
||||
}
|
||||
|
||||
MCAPI_ATTR McResult MCAPI_CALL mcReleaseEvents(
|
||||
uint32_t numEvents,
|
||||
const McEvent* pEvents)
|
||||
{
|
||||
McResult return_value = McResult::MC_NO_ERROR;
|
||||
per_thread_api_log_str.clear();
|
||||
|
||||
if (numEvents > 0 && pEvents == NULL) {
|
||||
per_thread_api_log_str = "invalid pointer to events";
|
||||
} else if (numEvents == 0 && pEvents != NULL) {
|
||||
per_thread_api_log_str = "number of events not set";
|
||||
} else {
|
||||
try {
|
||||
release_events_impl(numEvents, pEvents);
|
||||
}
|
||||
CATCH_POSSIBLE_EXCEPTIONS(per_thread_api_log_str);
|
||||
}
|
||||
|
||||
if (!per_thread_api_log_str.empty()) {
|
||||
|
||||
std::fprintf(stderr, "%s(...) -> %s\n", __FUNCTION__, per_thread_api_log_str.c_str());
|
||||
|
||||
if (return_value == McResult::MC_NO_ERROR) // i.e. problem with basic local parameter checks
|
||||
{
|
||||
return_value = McResult::MC_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
MCAPI_ATTR McResult MCAPI_CALL mcReleaseConnectedComponents(
|
||||
const McContext context,
|
||||
uint32_t numConnComps,
|
||||
const McConnectedComponent* pConnComps)
|
||||
{
|
||||
McResult return_value = McResult::MC_NO_ERROR;
|
||||
per_thread_api_log_str.clear();
|
||||
|
||||
if (context == nullptr) {
|
||||
per_thread_api_log_str = "context ptr (param0) undef (NULL)";
|
||||
} else if (numConnComps > 0 && pConnComps == NULL) {
|
||||
per_thread_api_log_str = "invalid pointer to connected components";
|
||||
} else if (numConnComps == 0 && pConnComps != NULL) {
|
||||
per_thread_api_log_str = "number of connected components not set";
|
||||
} else {
|
||||
try {
|
||||
release_connected_components_impl(context, numConnComps, pConnComps);
|
||||
}
|
||||
CATCH_POSSIBLE_EXCEPTIONS(per_thread_api_log_str);
|
||||
}
|
||||
|
||||
if (!per_thread_api_log_str.empty()) {
|
||||
|
||||
std::fprintf(stderr, "%s(...) -> %s\n", __FUNCTION__, per_thread_api_log_str.c_str());
|
||||
|
||||
if (return_value == McResult::MC_NO_ERROR) // i.e. problem with basic local parameter checks
|
||||
{
|
||||
return_value = McResult::MC_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
MCAPI_ATTR McResult MCAPI_CALL mcReleaseContext(const McContext context)
|
||||
{
|
||||
McResult return_value = McResult::MC_NO_ERROR;
|
||||
per_thread_api_log_str.clear();
|
||||
|
||||
if (context == nullptr) {
|
||||
per_thread_api_log_str = "context ptr (param0) undef (NULL)";
|
||||
} else {
|
||||
try {
|
||||
release_context_impl(context);
|
||||
}
|
||||
CATCH_POSSIBLE_EXCEPTIONS(per_thread_api_log_str);
|
||||
}
|
||||
|
||||
if (!per_thread_api_log_str.empty()) {
|
||||
|
||||
std::fprintf(stderr, "%s(...) -> %s\n", __FUNCTION__, per_thread_api_log_str.c_str());
|
||||
|
||||
if (return_value == McResult::MC_NO_ERROR) // i.e. problem with basic local parameter checks
|
||||
{
|
||||
return_value = McResult::MC_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
2198
src/mcut/source/preproc.cpp
Normal file
2198
src/mcut/source/preproc.cpp
Normal file
File diff suppressed because it is too large
Load diff
8682
src/mcut/source/shewchuk.c
Normal file
8682
src/mcut/source/shewchuk.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue