From e40c223181ec6b46437796809f6c2a7595bfc9bd Mon Sep 17 00:00:00 2001 From: "perepelits.m" Date: Sat, 4 Jul 2015 02:39:08 +0200 Subject: [PATCH] edje: add Convex Hull logic Summary: This is an algorithm which calcuates a convex hull of some mesh, in fact it returns vertex, index, normal and color datas, though the new mesh could be build just as for AABB Reviewers: raster, Hermet, cedric Subscribers: cedric, artem.popov Differential Revision: https://phab.enlightenment.org/D2585 Signed-off-by: Cedric BAIL --- src/lib/evas/include/evas_3d_utils.h | 681 +++++++++++++++++++++++++++ 1 file changed, 681 insertions(+) diff --git a/src/lib/evas/include/evas_3d_utils.h b/src/lib/evas/include/evas_3d_utils.h index 828348df77..bd6aaa60ac 100644 --- a/src/lib/evas/include/evas_3d_utils.h +++ b/src/lib/evas/include/evas_3d_utils.h @@ -7,6 +7,10 @@ #define DEGREE_TO_RADIAN(x) (((x) * M_PI) / 180.0) #define EVAS_MATRIX_IS_IDENTITY 0x00000001 +#define MIN_DIFF 0.00000000001 + +#define FLT_COMPARISON(a, b) \ + (fabs(a - b) > FLT_EPSILON) typedef struct _Evas_Color Evas_Color; typedef struct _Evas_Vec2 Evas_Vec2; @@ -345,6 +349,15 @@ evas_vec3_distance_square_get(const Evas_Vec3 *a, const Evas_Vec3 *b) return evas_vec3_length_square_get(&v); } +static inline Evas_Real +evas_vec3_angle_get(const Evas_Vec3 *a, const Evas_Vec3 *b) +{ + Evas_Real angle; + + angle = evas_vec3_dot_product(a, b) / (evas_vec3_length_get(a) * evas_vec3_length_get(b)); + return angle; +} + static inline void evas_vec3_normalize(Evas_Vec3 *out, const Evas_Vec3 *v) { @@ -570,6 +583,25 @@ evas_vec4_transform(Evas_Vec4 *out, const Evas_Vec4 *v, const Evas_Mat4 *m) evas_vec4_copy(out, &tmp); } +static inline void +evas_vec4_plain_by_points(Evas_Vec4 *out, const Evas_Vec3 *a, const Evas_Vec3 *b, const Evas_Vec3 *c) +{ + out->x = (b->y - a->y) * (c->z - a->z) - (b->z - a->z) * (c->y - a->y); + out->y = -(b->x - a->x) * (c->z - a->z) + (b->z - a->z) * (c->x - a->x); + out->z = (b->x - a->x) * (c->y - a->y) - (b->y - a->y) * (c->x - a->x); + out->w = (-a->x) * ((b->y - a->y)*(c->z - a->z) - (b->z - a->z) * (c->y - a->y)) - + (-a->y) * ((b->x - a->x) * (c->z - a->z) - (b->z - a->z) * (c->x - a->x)) + + (-a->z) * ((b->x - a->x) * (c->y - a->y) - (b->y - a->y) * (c->x - a->x)); +} + +static inline Evas_Real +evas_vec4_angle_plains(Evas_Vec4 *a, Evas_Vec4 *b) +{ + return (Evas_Real) ((a->x * b->x) + (a->y * b->y) + (a->z * b->z)) / ((sqrt((a->x * a->x) + + (a->y * a->y) + (a->z * a->z))) * (sqrt((b->x * b->x) + (b->y * b->y) + + (b->z * b->z)))); +} + static inline void evas_vec3_homogeneous_position_set(Evas_Vec3 *out, const Evas_Vec4 *v) { @@ -590,6 +622,95 @@ evas_vec3_homogeneous_direction_set(Evas_Vec3 *out, const Evas_Vec4 *v) out->z = v->z; } +static inline Eina_Bool +evas_vec3_if_equivalent(Evas_Vec3 *a, const Evas_Vec3 *b) +{ + /* Assume "v" is a directional vector. (v->w == 0.0) */ + return ((a->x == b->x) && (a->y == b->y) && (a->z == b->z)); +} + +static inline void +evas_triangle3_set(Evas_Triangle3 *v, Evas_Vec3 *a, Evas_Vec3 *b, Evas_Vec3 *c) +{ + evas_vec3_copy(&v->p0, a); + evas_vec3_copy(&v->p1, b); + evas_vec3_copy(&v->p2, c); +} + +static inline Eina_Bool +evas_triangle3_is_line(Evas_Triangle3 *v) +{ + if (evas_vec3_if_equivalent(&v->p0, &v->p1) || + evas_vec3_if_equivalent(&v->p0, &v->p2) || + evas_vec3_if_equivalent(&v->p1, &v->p2)) + return EINA_TRUE; + + return EINA_FALSE; +} + +static inline Eina_Bool +convex_hull_triangle3_if_not_first_edje(Evas_Triangle3 *v, Evas_Vec3 *a, Evas_Vec3 *b) +{ + if (((v->p1.x == a->x) && (v->p1.y == a->y) && (v->p1.z == a->z)) && + ((v->p2.x == b->x) && (v->p2.y == b->y) && (v->p2.z == b->z))) + return EINA_TRUE; + else if (((v->p2.x == a->x) && (v->p2.y == a->y) && (v->p2.z == a->z)) && + ((v->p1.x == b->x) && (v->p1.y == b->y) && (v->p1.z == b->z))) + return EINA_TRUE; + + return EINA_FALSE; +} + +static inline Eina_Bool +convex_hull_triangle3_if_first_edje(Evas_Triangle3 *v, Evas_Vec3 *a, Evas_Vec3 *b) +{ + if ((!FLT_COMPARISON(v->p0.x, a->x) && !FLT_COMPARISON(v->p0.y, a->y) && + !FLT_COMPARISON(v->p0.z, a->z)) && (!FLT_COMPARISON(v->p1.x, b->x) && + !FLT_COMPARISON(v->p1.y, b->y) && !FLT_COMPARISON(v->p1.z, b->z))) + return EINA_TRUE; + else if ((!FLT_COMPARISON(v->p1.x, a->x) && !FLT_COMPARISON(v->p1.y, a->y) && + !FLT_COMPARISON(v->p1.z, a->z)) && (!FLT_COMPARISON(v->p0.x, b->x) && + !FLT_COMPARISON(v->p0.y, b->y) && !FLT_COMPARISON(v->p0.z, b->z))) + return EINA_TRUE; + + return EINA_FALSE; +} + +static inline Eina_Bool +convex_hull_triangle3_if_first_point(Evas_Triangle3 *v, Evas_Vec3 *a) +{ + return ((v->p0.x == a->x) && (v->p0.y == a->y) && (v->p0.z == a->z)); +} + +static inline Eina_Bool +evas_vec3_if_equivalent_as_triangle(Evas_Vec3 *v0, Evas_Vec3 *v1, Evas_Vec3 *v2, + Evas_Vec3 *w0, Evas_Vec3 *w1, Evas_Vec3 *w2) +{ + if (((v0->x == w0->x) && (v0->y == w0->y) && (v0->z == w0->z)) && + ((v1->x == w1->x) && (v1->y == w1->y) && (v1->z == w1->z)) && + ((v2->x == w2->x) && (v2->y == w2->y) && (v2->z == w2->z))) + return EINA_TRUE; + + return EINA_FALSE; +} + + +static inline Eina_Bool +evas_triangle3_if_equivalent(Evas_Triangle3 *a, Evas_Triangle3 *b) +{ + /* to compare two triangles there are six permutations + to test because vertices are unordered */ + if (evas_vec3_if_equivalent_as_triangle(&a->p0, &a->p1, &a->p2, &b->p0, &b->p1, &b->p2) || + evas_vec3_if_equivalent_as_triangle(&a->p0, &a->p1, &a->p2, &b->p0, &b->p2, &b->p1) || + evas_vec3_if_equivalent_as_triangle(&a->p0, &a->p1, &a->p2, &b->p1, &b->p0, &b->p2) || + evas_vec3_if_equivalent_as_triangle(&a->p0, &a->p1, &a->p2, &b->p1, &b->p2, &b->p0) || + evas_vec3_if_equivalent_as_triangle(&a->p0, &a->p1, &a->p2, &b->p2, &b->p0, &b->p1) || + evas_vec3_if_equivalent_as_triangle(&a->p0, &a->p1, &a->p2, &b->p2, &b->p1, &b->p0)) + return EINA_TRUE; + + return EINA_FALSE; +} + static inline void evas_vec4_homogeneous_position_set(Evas_Vec4 *out, const Evas_Vec3 *v) { @@ -2035,3 +2156,563 @@ box_intersection_box(Evas_Box3 *v1, Evas_Box3 *v2) return EINA_TRUE; } +static inline void +convex_hull_vertex_set(Evas_Triangle3 *el, int *vertex_count, float **vertex, + unsigned short int **index, unsigned int k, int *leader, int coord) +{ + int color_coords, normal_coords; + Evas_Vec3 vect; + switch (coord) + { + case 0: + vect = el->p0; + break; + case 1: + vect = el->p1; + break; + case 2: + vect = el->p2; + break; + } + (*vertex_count)++; + *vertex = (float*) realloc(*vertex, (10 * (*vertex_count)) * sizeof(float)); + + (*vertex)[10 * (*vertex_count) - 10] = vect.x; + (*vertex)[10 * (*vertex_count) - 9] = vect.y; + (*vertex)[10 * (*vertex_count) - 8] = vect.z; + /* set alpha canal */ + (*vertex)[10 * (*vertex_count) - 1] = 1.0; + /* set color */ + for (color_coords = 2; color_coords < 5; color_coords++) + (*vertex)[10 * (*vertex_count) - color_coords] = (float) rand() / RAND_MAX; + /* set normal coords */ + for (normal_coords = 5; normal_coords < 8; normal_coords++) + (*vertex)[10 * (*vertex_count) - normal_coords] = 1.0; + (*index)[3 * k + coord] = *leader; + (*leader)++; +} + +static inline Evas_Triangle3 +convex_hull_first_tr_get(float *data, int count, int stride) +{ + Evas_Triangle3 out; + + Evas_Vec3 triangle1; + Evas_Vec3 triangle2, triangle2_candidate; + Evas_Vec3 triangle3, triangle3_candidate; + Evas_Vec3 first, second, complanar1, complanar2, candidate; + Evas_Vec4 normal_a, normal_b; + + Evas_Real cos = 0.0, new_cos = 0.0, tan = 0.0, new_tan = 0.0, cos_2d = 0.0, new_cos_2d = 0.0; + int first_num = 0, second_num = 0; + int i = 0, j = 0; + + evas_vec3_set(&triangle1, data[0], data[1], data[2]); + + for (i = 1, j = stride; i < count; i++, j += stride) + { + if ((triangle1.z > data[j + 2]) || + ((triangle1.z == data[j + 2]) && (triangle1.y > data[j + 1])) || + ((triangle1.z == data[j + 2]) && (triangle1.y == data[j + 1]) && (triangle1.x > data[j]))) + { + evas_vec3_set(&triangle1, data[j], data[j + 1], data[j + 2]); + first_num = i; + } + } + + if (first_num) + evas_vec3_set(&triangle2, data[0], data[1], data[2]); + else + { + evas_vec3_set(&triangle2, data[3], data[4], data[5]); + second_num = 1; + } + + tan = fabs(triangle2.z - triangle1.z) / fabs(triangle2.y - triangle1.y); + +#define COMPARE_ANGLES(trigonom, triangle, previous, big, little) \ + if (little > big + FLT_EPSILON) \ + { \ + trigonom = new_##trigonom; \ + cos_2d = new_cos_2d; \ + evas_vec3_set(&triangle, data[j], data[j + 1], data[j + 2]); \ + } \ + else if(!FLT_COMPARISON(little, big) && \ + (evas_vec3_distance_get(&triangle##_candidate, &previous) > \ + evas_vec3_distance_get(&triangle, &previous))) \ + { \ + evas_vec3_set(&triangle, data[j], data[j + 1], data[j + 2]); \ + } + evas_vec3_set(&complanar1, 1, 0, 0); + for (i = 0, j = 0; i < count; i++, j += stride) + { + if (FLT_COMPARISON(data[j], triangle1.x) || + FLT_COMPARISON(data[j + 1], triangle1.y) || + FLT_COMPARISON(data[j + 2], triangle1.z)) + { + new_tan = fabs(data[j + 2] - triangle1.z) / fabs(data[j + 1] - triangle1.y); + + if (FLT_COMPARISON(data[j + 1], triangle1.y) && + FLT_COMPARISON(triangle2.y, triangle1.y)) + { + if (tan > new_tan + FLT_EPSILON) + { + tan = new_tan; + evas_vec3_set(&triangle2, data[j], data[j + 1], data[j + 2]); + second_num = i; + evas_vec3_subtract(&first, &complanar1, &triangle1); + evas_vec3_subtract(&second, &triangle2, &triangle1); + cos_2d = evas_vec3_angle_get(&complanar1, &second); + } + else if (!FLT_COMPARISON(tan, new_tan)) + { + evas_vec3_subtract(&first, &complanar1, &triangle2); + evas_vec3_set(&triangle2_candidate, data[j], data[j + 1], data[j + 2]); + evas_vec3_subtract(&first, &complanar1, &triangle1); + evas_vec3_subtract(&second, &triangle2_candidate, &triangle1); + new_cos_2d = evas_vec3_angle_get(&complanar1, &second); + if (new_cos_2d > cos_2d + FLT_EPSILON) + second_num = i; + + COMPARE_ANGLES(cos, triangle2, triangle1, cos_2d, new_cos_2d) + } + } + + else if (!FLT_COMPARISON(data[j + 1], triangle1.y) && + !FLT_COMPARISON(data[j + 2], triangle1.z) && + FLT_COMPARISON(triangle2.y, triangle1.y)) + evas_vec3_set(&triangle2, data[j], data[j + 1], data[j + 2]); + + else if (!FLT_COMPARISON(data[j + 1], triangle1.y) && + !FLT_COMPARISON(data[j + 2], triangle1.z) && + !FLT_COMPARISON(triangle2.z, triangle1.z) && + !FLT_COMPARISON(triangle2.y, triangle1.y)) + { + evas_vec3_set(&triangle2_candidate, data[j], data[j + 1], data[j + 2]); + if (evas_vec3_distance_get(&triangle2_candidate, &triangle1) > + evas_vec3_distance_get(&triangle2, &triangle1)) + evas_vec3_set(&triangle2, data[j], data[j + 1], data[j + 2]); + } + } + } + + evas_vec3_set(&complanar1, triangle1.x + 1, triangle1.y, triangle1.z); + evas_vec3_set(&complanar2, triangle1.x, triangle1.y + 1, triangle1.z); + evas_vec4_plain_by_points(&normal_a, &triangle1, &complanar1, &complanar2); + + if (normal_a.z < 0) + evas_vec4_scale(&normal_a, &normal_a, -1); + + evas_vec3_set(&triangle3, data[0], data[1], data[2]); + + cos = -1.0; + cos_2d = 1.0; + + for (i = 0, j = 0; i < count; i++, j += stride) + { + if ((i != first_num) && (i != second_num)) + { + evas_vec3_set(&candidate, data[j], data[j + 1], data[j + 2]); + evas_vec4_plain_by_points(&normal_b, &triangle1, &candidate, &triangle2); + + if (normal_b.z < 0) + evas_vec4_scale(&normal_b, &normal_b, -1); + + new_cos = evas_vec4_angle_plains(&normal_a, &normal_b); + + if (new_cos > cos + FLT_EPSILON) + { + evas_vec3_set(&triangle3_candidate, data[j], data[j + 1], data[j + 2]); + evas_vec3_subtract(&first, &triangle2, &triangle1); + evas_vec3_subtract(&second, &triangle3, &triangle1); + cos = new_cos; + evas_vec3_set(&triangle3, data[j], data[j + 1], data[j + 2]); + cos_2d = evas_vec3_angle_get(&second, &first); + } + else if (!FLT_COMPARISON(new_cos, cos)) + { + evas_vec3_set(&triangle3_candidate, data[j], data[j + 1], data[j + 2]); + evas_vec3_subtract(&first, &triangle1, &triangle2); + evas_vec3_subtract(&second, &triangle3_candidate, &triangle2); + new_cos_2d = evas_vec3_angle_get(&first, &second); + + COMPARE_ANGLES(tan, triangle3, triangle2, new_cos_2d, cos_2d) + } + } + } + + evas_triangle3_set(&out, &triangle1, &triangle2, &triangle3); + +#undef COMPARE_ANGLES + return out; +} + +static inline void +evas_convex_hull_get(float *data, int count, int stride, float **vertex, + unsigned short int **index, int *vertex_count, int *index_count) +{ + Evas_Triangle3 first_elem, second_elem, *third_elem = NULL, *el = NULL; + + Evas_Vec3 *next = NULL, *best = NULL, *next_2d = NULL, *el_vec3 = NULL; + Evas_Vec3 tmp1, tmp2; + Evas_Vec4 normal_a, normal_b; + + Eina_Array arr_elems; + Eina_Array arr_triangles; + Eina_Array arr_candidates; + Eina_Array arr_ch; + Eina_Array_Iterator iterator; + + Evas_Real cos = 0.0, new_cos = 0.0, cos_2d = 0.0; + float *found_vertex = NULL; + int i = 0, j = 0, new_stride = 0, leader = 0; + int if_two = 0, first_exist_twice = 0, second_exist_twice = 0; + unsigned int k = 0; + unsigned short int *found_index = NULL; + + Eina_Bool exist1 = EINA_FALSE, pushed; + Eina_Bool equivalent_triangle = EINA_FALSE, triangle_chain = EINA_FALSE; + Eina_Bool on_plain = EINA_FALSE, right = EINA_FALSE; + + eina_array_step_set(&arr_elems, sizeof(Eina_Array), 1); + eina_array_step_set(&arr_triangles, sizeof(Eina_Array), 1); + eina_array_step_set(&arr_candidates, sizeof(Eina_Array), 1); + eina_array_step_set(&arr_ch, sizeof(Eina_Array), 1); + + /* Finding of first triangle in convex hull */ + first_elem = convex_hull_first_tr_get(data, count, stride); + + eina_array_push(&arr_triangles, &first_elem); + eina_array_push(&arr_elems, &first_elem); + + evas_triangle3_set(&second_elem, &first_elem.p1, &first_elem.p2, &first_elem.p0); + eina_array_push(&arr_elems, &second_elem); + eina_array_push(&arr_triangles, &second_elem); + + third_elem = malloc(sizeof(Evas_Triangle3)); + evas_triangle3_set(third_elem, &first_elem.p2, &first_elem.p0, &first_elem.p1); + eina_array_push(&arr_elems, third_elem); + eina_array_push(&arr_triangles, third_elem); + eina_array_push(&arr_ch, third_elem); + + el = eina_array_data_get(&arr_elems, 0); + + /* arr_ellems is an array of triangles, in fact it is a queue of edjes + because vertices in triangles are ordered, every edje in this queue + should have a conjugate edje in some other triangle */ + while (eina_array_count(&arr_elems) > 0) + { + Evas_Triangle3 *new_elem1 = NULL, *new_elem2 = NULL; + + Evas_Triangle3 *elem = eina_array_pop(&arr_elems); + + cos = -1.0; + + /* searching of next triangle in convex hull as given conjugate edje + and one new vertex, all vertices should be checked */ + for (i = 0, j = 0; i < count; i++, j += stride) + { + if ((FLT_COMPARISON(elem->p0.x, data[j]) || FLT_COMPARISON(elem->p0.y, data[j + 1]) || + FLT_COMPARISON(elem->p0.z, data[j + 2])) && (FLT_COMPARISON(elem->p1.x, data[j]) || + FLT_COMPARISON(elem->p1.y, data[j + 1]) || FLT_COMPARISON(elem->p1.z, data[j + 2])) && + (FLT_COMPARISON(elem->p2.x, data[j]) || FLT_COMPARISON(elem->p2.y, data[j + 1]) || + FLT_COMPARISON(elem->p2.z, data[j + 2]))) + { + next = malloc(sizeof(Evas_Vec3)); + evas_vec3_set(next, data[j], data[j + 1], data[j + 2]); + pushed = EINA_FALSE; + + /* something like the dihedral angle between the triangles + is a determining factor in searching the necessary points */ + + evas_vec4_plain_by_points(&normal_a, &elem->p0, &elem->p1, &elem->p2); + evas_vec4_plain_by_points(&normal_b, &elem->p0, &elem->p1, next); + + /* MIN_DIFF because vertices that belong to plain shouldn't be included */ + if (fabs(normal_a.x * data[j] + normal_a.y * data[j + 1] + normal_a.z * data[j + 2] + normal_a.w) < MIN_DIFF) + { + /* based on the construction of triangles, parallel but not collinear normal + means that the triangles overlap, which is the worst case */ + if ((normal_a.x * normal_b.x <= 0) && (normal_a.y * normal_b.y <= 0) && (normal_a.z * normal_b.z <= 0) && + ((fabs(normal_a.x) > DBL_EPSILON) || (fabs(normal_a.y) > DBL_EPSILON) || (fabs(normal_a.z) > DBL_EPSILON)) && + ((fabs(normal_b.x) > DBL_EPSILON) || (fabs(normal_b.y) > DBL_EPSILON) || (fabs(normal_b.z) > DBL_EPSILON))) + new_cos = 1.0; + else new_cos = -1.0; + } + + else + { + if (normal_a.x * data[j] + normal_a.y * data[j+1] + normal_a.z * data[j+2] + normal_a.w < 0) + evas_vec4_scale(&normal_a, &normal_a, -1); + if (normal_b.x * elem->p2.x + normal_b.y * elem->p2.y + normal_b.z * elem->p2.z + normal_b.w < 0) + evas_vec4_scale(&normal_b, &normal_b, -1); + + new_cos = evas_vec4_angle_plains(&normal_a, &normal_b); + } + + /* MIN_DIFF is more useful for dihedral angles apparently */ + if (new_cos > cos + MIN_DIFF) + { + cos = new_cos; + EINA_ARRAY_ITER_NEXT(&arr_candidates, k, el_vec3, iterator) + free(el_vec3); + + /* Vertex gets into arr_candidates if the corresponding cosine is the maximum */ + eina_array_flush(&arr_candidates); + eina_array_step_set(&arr_candidates, sizeof(Eina_Array), 1); + eina_array_push(&arr_candidates, next); + pushed = EINA_TRUE; + } + else if (fabs(new_cos - cos) < MIN_DIFF) + { + exist1 = EINA_FALSE; + + for (k = 0; (k < eina_array_count(&arr_candidates)) && !exist1; k++) + { + next_2d = eina_array_data_get(&arr_candidates, k); + exist1 = evas_vec3_if_equivalent(next, next_2d); + } + if (!exist1) + { + eina_array_push(&arr_candidates, next); + pushed = EINA_TRUE; + } + } + + if (!pushed) + free(next); + } + } + + on_plain = EINA_FALSE; + right = EINA_FALSE; + + /* The case when several points are found, is discussed below. + This case is interesting because the convex hull in the + two-dimensional subspace should be filled further */ + if ((cos != 1.0) && (1 < eina_array_count(&arr_candidates))) + { + Evas_Vec3 angle_from, angle_to; + next_2d = eina_array_data_get(&arr_candidates, 0); + evas_vec4_plain_by_points(&normal_b, &elem->p1, &elem->p0, next_2d); + + if (normal_b.x * elem->p2.x + normal_b.y * elem->p2.y + normal_b.z * elem->p2.z + normal_b.w > 0) + { + evas_vec3_subtract(&angle_from, &elem->p0, &elem->p1); + right = EINA_TRUE; + } + else + evas_vec3_subtract(&angle_from, &elem->p1, &elem->p0); + + cos_2d = -1.0; + + EINA_ARRAY_ITER_NEXT(&arr_candidates, k, next_2d, iterator) + { + /* Selection of the required vertex occurs on the basis of a specific angle */ + if (right) + evas_vec3_subtract(&angle_to, next_2d, &elem->p0); + else + evas_vec3_subtract(&angle_to, next_2d, &elem->p1); + + new_cos = evas_vec3_dot_product(&angle_from, &angle_to) / + (evas_vec3_length_get(&angle_from) * evas_vec3_length_get(&angle_to)); + if (new_cos > cos_2d + FLT_EPSILON) + { + cos_2d = new_cos; + best = eina_array_data_get(&arr_candidates, k); + } + else if (!FLT_COMPARISON(new_cos, cos_2d)) + { + if ((right && (evas_vec3_distance_get(best, &elem->p0) < evas_vec3_length_get(&angle_from))) || + (!right && (evas_vec3_distance_get(best, &elem->p1) < evas_vec3_length_get(&angle_from)))) + best = eina_array_data_get(&arr_candidates, k); + } + } + } + + /* This event will take place after the previous, + in fact, choice of first triangle in a new two-dimensional + convex hull allows to fill it fan counterclockwise when viewed from the inside */ + else if ((cos == 1.0) && (1 < eina_array_count(&arr_candidates))) + { + Evas_Vec3 angle_from, angle_to; + evas_vec3_subtract(&angle_from, &elem->p0, &elem->p1); + cos_2d = -1.0; + EINA_ARRAY_ITER_NEXT(&arr_candidates, k, next_2d, iterator) + { + evas_vec3_subtract(&angle_to, next_2d, &elem->p0); + + evas_vec4_plain_by_points(&normal_a, &elem->p0, &elem->p1, &elem->p2); + evas_vec4_plain_by_points(&normal_b, &elem->p0, &elem->p1, next_2d); + if ((normal_a.x * normal_b.x <= 0) && (normal_a.y * normal_b.y <= 0) && (normal_a.z * normal_b.z <= 0)) + { + new_cos = evas_vec3_dot_product(&angle_from, &angle_to) / + (evas_vec3_length_get(&angle_from) * evas_vec3_length_get(&angle_to)); + if (new_cos > cos_2d + FLT_EPSILON) + { + cos_2d = new_cos; + best = eina_array_data_get(&arr_candidates, k); + } + else if (!FLT_COMPARISON(new_cos, cos_2d)) + { + if (evas_vec3_distance_get(best, &elem->p0) < evas_vec3_length_get(&angle_to)) + best = eina_array_data_get(&arr_candidates, k); + } + on_plain = EINA_TRUE; + } + } + } + + else + best = eina_array_data_get(&arr_candidates, 0); + + evas_vec4_plain_by_points(&normal_b, &elem->p0, &elem->p1, best); + + if_two = 0; + first_exist_twice = 0; + second_exist_twice = 0; + equivalent_triangle = EINA_FALSE; + triangle_chain = EINA_FALSE; + evas_vec3_copy(&tmp1, &elem->p0); + evas_vec3_copy(&tmp2, &elem->p1); + new_elem1 = malloc(sizeof(Evas_Triangle3)); + evas_triangle3_set(new_elem1, best, &tmp1, &tmp2); + pushed = EINA_FALSE; + + /* verification that the edje has not been found previously */ + EINA_ARRAY_ITER_NEXT(&arr_triangles, k, el, iterator) + { + if (convex_hull_triangle3_if_first_edje(el, &elem->p0, &elem->p1)) + if_two++; + if (evas_triangle3_if_equivalent(el, new_elem1)) + equivalent_triangle++; + } + + + EINA_ARRAY_ITER_NEXT(&arr_triangles, k, el, iterator) + { + if ((k > 2) && (convex_hull_triangle3_if_not_first_edje(el, &elem->p0, best) || + convex_hull_triangle3_if_not_first_edje(el, &elem->p1, best))) + triangle_chain = EINA_TRUE; + } + + /* There is a specific order according to which the edjes are entered in arr_elems */ + if (!on_plain && !right) + { + if ((!equivalent_triangle) && (!second_exist_twice) && (!triangle_chain) && (if_two < 2)) + { + if (new_elem2) + free (new_elem2); + new_elem2 = malloc(sizeof(Evas_Triangle3)); + evas_triangle3_set(new_elem2, best, &tmp2, &tmp1); + eina_array_push(&arr_elems, new_elem2); + + /* triangles whose edges have been found should be entered into the arr_triangles + to optimize the algorithm */ + if ((first_exist_twice < 2) && (second_exist_twice < 2)) + eina_array_push(&arr_triangles, eina_array_data_get(&arr_elems, eina_array_count(&arr_elems) - 1)); + } + if ((!equivalent_triangle) && (!first_exist_twice) && (!triangle_chain) && (if_two < 2)) + { + eina_array_push(&arr_elems, new_elem1); + if ((first_exist_twice < 2) && (second_exist_twice < 2)) + { + pushed = EINA_TRUE; + + /* eina_ch is the resultant vector of all triangles in convex hull */ + eina_array_push(&arr_ch, eina_array_data_get(&arr_elems, eina_array_count(&arr_elems) - 1)); + eina_array_push(&arr_triangles, eina_array_data_get(&arr_elems, eina_array_count(&arr_elems) - 1)); + } + } + } + + else + { + if ((!equivalent_triangle) && (!first_exist_twice) && (!triangle_chain) && (if_two < 2)) + { + eina_array_push(&arr_elems, new_elem1); + if ((first_exist_twice < 2) && (second_exist_twice < 2)) + { + pushed = EINA_TRUE; + eina_array_push(&arr_ch, eina_array_data_get(&arr_elems, eina_array_count(&arr_elems) - 1)); + eina_array_push(&arr_triangles, eina_array_data_get(&arr_elems, eina_array_count(&arr_elems) - 1)); + } + } + + if ((!equivalent_triangle) && (!second_exist_twice) && (!triangle_chain) && (if_two < 2)) + { + if (new_elem2) + free (new_elem2); + new_elem2 = malloc(sizeof(Evas_Triangle3)); + evas_triangle3_set(new_elem2, best, &tmp2, &tmp1); + eina_array_push(&arr_elems, new_elem2); + + if ((first_exist_twice < 2) && (second_exist_twice < 2)) + eina_array_push(&arr_triangles, eina_array_data_get(&arr_elems, eina_array_count(&arr_elems)-1)); + } + } + if (!pushed) + free (new_elem1); + } + + + *vertex_count = 0; + *index_count = 3 * eina_array_count(&arr_ch); + + found_vertex = (float*) malloc(10 * sizeof(float)); + found_index = (unsigned short int*) malloc((*index_count) * sizeof(unsigned short int)); + j = 0; + +#define CHECK_AND_SET_VERTEX(coord) \ + exist1 = EINA_FALSE; \ + for (i = 0, new_stride = 0; i < (*vertex_count) && !exist1; i++, new_stride += 10) \ + { \ + if ((k > 0) && (el->p##coord.x == found_vertex[new_stride]) && \ + (el->p##coord.y == found_vertex[new_stride + 1]) && \ + (el->p##coord.z == found_vertex[new_stride + 2])) \ + { \ + exist1 = EINA_TRUE; \ + found_index[3 * k + coord] = i; \ + } \ + } \ + if (!exist1) \ + convex_hull_vertex_set(el, vertex_count, &found_vertex, \ + &found_index, k, &leader, coord); + + EINA_ARRAY_ITER_NEXT(&arr_ch, k, el, iterator) + { + CHECK_AND_SET_VERTEX(0) + CHECK_AND_SET_VERTEX(1) + CHECK_AND_SET_VERTEX(2) + + j += 30; + } + + *vertex = (float*) malloc((10 * (*vertex_count)) * sizeof(float)); + memcpy(*vertex, found_vertex, (10 * (*vertex_count)) * sizeof(float)); + free(found_vertex); + + *index = (unsigned short int*) malloc((*index_count) * sizeof(unsigned short int)); + memcpy(*index, found_index, (*index_count) * sizeof(unsigned short int)); + free(found_index); + + EINA_ARRAY_ITER_NEXT(&arr_triangles, k, el, iterator) + { + if (k > 2) + free(el); + } + + free(third_elem); + + EINA_ARRAY_ITER_NEXT(&arr_candidates, k, el_vec3, iterator) + free(el_vec3); + + eina_array_flush(&arr_candidates); + eina_array_flush(&arr_ch); + eina_array_flush(&arr_elems); + eina_array_flush(&arr_triangles); + +#undef CHECK_AND_SET_VERTEX + + return; +}