Files
test2/source/blender/blenkernel/intern/editmesh_bvh.c
Sergey Sharybin a12a8a71bb Remove "All Rights Reserved" from Blender Foundation copyright code
The goal is to solve confusion of the "All rights reserved" for licensing
code under an open-source license.

The phrase "All rights reserved" comes from a historical convention that
required this phrase for the copyright protection to apply. This convention
is no longer relevant.

However, even though the phrase has no meaning in establishing the copyright
it has not lost meaning in terms of licensing.

This change makes it so code under the Blender Foundation copyright does
not use "all rights reserved". This is also how the GPL license itself
states how to apply it to the source code:

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software ...

This change does not change copyright notice in cases when the copyright
is dual (BF and an author), or just an author of the code. It also does
mot change copyright which is inherited from NaN Holding BV as it needs
some further investigation about what is the proper way to handle it.
2023-03-30 10:51:59 +02:00

586 lines
16 KiB
C

/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2010 Blender Foundation */
/** \file
* \ingroup bke
*/
#include "MEM_guardedalloc.h"
#include "BLI_kdopbvh.h"
#include "BLI_math.h"
#include "BKE_editmesh.h"
#include "BKE_editmesh_bvh.h" /* own include */
struct BMBVHTree {
BVHTree *tree;
BMLoop *(*looptris)[3];
int looptris_tot;
BMesh *bm;
const float (*cos_cage)[3];
bool cos_cage_free;
int flag;
};
BMBVHTree *BKE_bmbvh_new_from_editmesh(BMEditMesh *em,
int flag,
const float (*cos_cage)[3],
const bool cos_cage_free)
{
return BKE_bmbvh_new(em->bm, em->looptris, em->tottri, flag, cos_cage, cos_cage_free);
}
BMBVHTree *BKE_bmbvh_new_ex(BMesh *bm,
BMLoop *(*looptris)[3],
int looptris_tot,
int flag,
const float (*cos_cage)[3],
const bool cos_cage_free,
bool (*test_fn)(BMFace *, void *user_data),
void *user_data)
{
/* could become argument */
const float epsilon = FLT_EPSILON * 2.0f;
BMBVHTree *bmtree = MEM_callocN(sizeof(*bmtree), "BMBVHTree");
float cos[3][3];
int tottri;
/* avoid testing every tri */
BMFace *f_test, *f_test_prev;
bool test_fn_ret;
/* BKE_editmesh_looptri_calc() must be called already */
BLI_assert(looptris_tot != 0 || bm->totface == 0);
if (cos_cage) {
BM_mesh_elem_index_ensure(bm, BM_VERT);
}
bmtree->looptris = looptris;
bmtree->looptris_tot = looptris_tot;
bmtree->bm = bm;
bmtree->cos_cage = cos_cage;
bmtree->cos_cage_free = cos_cage_free;
bmtree->flag = flag;
if (test_fn) {
/* callback must do... */
BLI_assert(!(flag & (BMBVH_RESPECT_SELECT | BMBVH_RESPECT_HIDDEN)));
f_test_prev = NULL;
test_fn_ret = false;
tottri = 0;
for (int i = 0; i < looptris_tot; i++) {
f_test = looptris[i][0]->f;
if (f_test != f_test_prev) {
test_fn_ret = test_fn(f_test, user_data);
f_test_prev = f_test;
}
if (test_fn_ret) {
tottri++;
}
}
}
else {
tottri = looptris_tot;
}
bmtree->tree = BLI_bvhtree_new(tottri, epsilon, 8, 8);
f_test_prev = NULL;
test_fn_ret = false;
for (int i = 0; i < looptris_tot; i++) {
if (test_fn) {
/* NOTE: the arrays won't align now! Take care. */
f_test = looptris[i][0]->f;
if (f_test != f_test_prev) {
test_fn_ret = test_fn(f_test, user_data);
f_test_prev = f_test;
}
if (!test_fn_ret) {
continue;
}
}
if (cos_cage) {
copy_v3_v3(cos[0], cos_cage[BM_elem_index_get(looptris[i][0]->v)]);
copy_v3_v3(cos[1], cos_cage[BM_elem_index_get(looptris[i][1]->v)]);
copy_v3_v3(cos[2], cos_cage[BM_elem_index_get(looptris[i][2]->v)]);
}
else {
copy_v3_v3(cos[0], looptris[i][0]->v->co);
copy_v3_v3(cos[1], looptris[i][1]->v->co);
copy_v3_v3(cos[2], looptris[i][2]->v->co);
}
BLI_bvhtree_insert(bmtree->tree, i, (float *)cos, 3);
}
BLI_bvhtree_balance(bmtree->tree);
return bmtree;
}
static bool bm_face_is_select(BMFace *f, void *UNUSED(user_data))
{
return (BM_elem_flag_test(f, BM_ELEM_SELECT) != 0);
}
static bool bm_face_is_not_hidden(BMFace *f, void *UNUSED(user_data))
{
return (BM_elem_flag_test(f, BM_ELEM_HIDDEN) == 0);
}
BMBVHTree *BKE_bmbvh_new(BMesh *bm,
BMLoop *(*looptris)[3],
int looptris_tot,
int flag,
const float (*cos_cage)[3],
const bool cos_cage_free)
{
bool (*test_fn)(BMFace *, void *user_data);
if (flag & BMBVH_RESPECT_SELECT) {
test_fn = bm_face_is_select;
}
else if (flag & BMBVH_RESPECT_HIDDEN) {
test_fn = bm_face_is_not_hidden;
}
else {
test_fn = NULL;
}
flag &= ~(BMBVH_RESPECT_SELECT | BMBVH_RESPECT_HIDDEN);
return BKE_bmbvh_new_ex(
bm, looptris, looptris_tot, flag, cos_cage, cos_cage_free, test_fn, NULL);
}
void BKE_bmbvh_free(BMBVHTree *bmtree)
{
BLI_bvhtree_free(bmtree->tree);
if (bmtree->cos_cage && bmtree->cos_cage_free) {
MEM_freeN((void *)bmtree->cos_cage);
}
MEM_freeN(bmtree);
}
BVHTree *BKE_bmbvh_tree_get(BMBVHTree *bmtree)
{
return bmtree->tree;
}
/* -------------------------------------------------------------------- */
/* Utility BMesh cast/intersect functions */
/**
* Return the coords from a triangle.
*/
static void bmbvh_tri_from_face(const float *cos[3],
const BMLoop **ltri,
const float (*cos_cage)[3])
{
if (cos_cage == NULL) {
cos[0] = ltri[0]->v->co;
cos[1] = ltri[1]->v->co;
cos[2] = ltri[2]->v->co;
}
else {
cos[0] = cos_cage[BM_elem_index_get(ltri[0]->v)];
cos[1] = cos_cage[BM_elem_index_get(ltri[1]->v)];
cos[2] = cos_cage[BM_elem_index_get(ltri[2]->v)];
}
}
/* Taken from `bvhutils.c`. */
/* -------------------------------------------------------------------- */
/* BKE_bmbvh_ray_cast */
struct RayCastUserData {
/* from the bmtree */
const BMLoop *(*looptris)[3];
const float (*cos_cage)[3];
/* from the hit */
float uv[2];
};
static BMFace *bmbvh_ray_cast_handle_hit(BMBVHTree *bmtree,
struct RayCastUserData *bmcb_data,
const BVHTreeRayHit *hit,
float *r_dist,
float r_hitout[3],
float r_cagehit[3])
{
if (r_hitout) {
if (bmtree->flag & BMBVH_RETURN_ORIG) {
BMLoop **ltri = bmtree->looptris[hit->index];
interp_v3_v3v3v3_uv(r_hitout, ltri[0]->v->co, ltri[1]->v->co, ltri[2]->v->co, bmcb_data->uv);
}
else {
copy_v3_v3(r_hitout, hit->co);
}
if (r_cagehit) {
copy_v3_v3(r_cagehit, hit->co);
}
}
if (r_dist) {
*r_dist = hit->dist;
}
return bmtree->looptris[hit->index][0]->f;
}
static void bmbvh_ray_cast_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
{
struct RayCastUserData *bmcb_data = userdata;
const BMLoop **ltri = bmcb_data->looptris[index];
float dist, uv[2];
const float *tri_cos[3];
bool isect;
bmbvh_tri_from_face(tri_cos, ltri, bmcb_data->cos_cage);
isect =
(ray->radius > 0.0f ?
isect_ray_tri_epsilon_v3(ray->origin,
ray->direction,
tri_cos[0],
tri_cos[1],
tri_cos[2],
&dist,
uv,
ray->radius) :
#ifdef USE_KDOPBVH_WATERTIGHT
isect_ray_tri_watertight_v3(
ray->origin, ray->isect_precalc, tri_cos[0], tri_cos[1], tri_cos[2], &dist, uv));
#else
isect_ray_tri_v3(
ray->origin, ray->direction, tri_cos[0], tri_cos[1], tri_cos[2], &dist, uv));
#endif
if (isect && dist < hit->dist) {
hit->dist = dist;
hit->index = index;
copy_v3_v3(hit->no, ltri[0]->f->no);
madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
copy_v2_v2(bmcb_data->uv, uv);
}
}
BMFace *BKE_bmbvh_ray_cast(BMBVHTree *bmtree,
const float co[3],
const float dir[3],
const float radius,
float *r_dist,
float r_hitout[3],
float r_cagehit[3])
{
BVHTreeRayHit hit;
struct RayCastUserData bmcb_data;
const float dist = r_dist ? *r_dist : FLT_MAX;
if (bmtree->cos_cage) {
BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT));
}
hit.dist = dist;
hit.index = -1;
/* ok to leave 'uv' uninitialized */
bmcb_data.looptris = (const BMLoop *(*)[3])bmtree->looptris;
bmcb_data.cos_cage = (const float(*)[3])bmtree->cos_cage;
BLI_bvhtree_ray_cast(bmtree->tree, co, dir, radius, &hit, bmbvh_ray_cast_cb, &bmcb_data);
if (hit.index != -1 && hit.dist != dist) {
return bmbvh_ray_cast_handle_hit(bmtree, &bmcb_data, &hit, r_dist, r_hitout, r_cagehit);
}
return NULL;
}
/* -------------------------------------------------------------------- */
/* bmbvh_ray_cast_cb_filter */
/* Same as BKE_bmbvh_ray_cast but takes a callback to filter out faces.
*/
struct RayCastUserData_Filter {
struct RayCastUserData bmcb_data;
BMBVHTree_FaceFilter filter_cb;
void *filter_userdata;
};
static void bmbvh_ray_cast_cb_filter(void *userdata,
int index,
const BVHTreeRay *ray,
BVHTreeRayHit *hit)
{
struct RayCastUserData_Filter *bmcb_data_filter = userdata;
struct RayCastUserData *bmcb_data = &bmcb_data_filter->bmcb_data;
const BMLoop **ltri = bmcb_data->looptris[index];
if (bmcb_data_filter->filter_cb(ltri[0]->f, bmcb_data_filter->filter_userdata)) {
bmbvh_ray_cast_cb(bmcb_data, index, ray, hit);
}
}
BMFace *BKE_bmbvh_ray_cast_filter(BMBVHTree *bmtree,
const float co[3],
const float dir[3],
const float radius,
float *r_dist,
float r_hitout[3],
float r_cagehit[3],
BMBVHTree_FaceFilter filter_cb,
void *filter_userdata)
{
BVHTreeRayHit hit;
struct RayCastUserData_Filter bmcb_data_filter;
struct RayCastUserData *bmcb_data = &bmcb_data_filter.bmcb_data;
const float dist = r_dist ? *r_dist : FLT_MAX;
bmcb_data_filter.filter_cb = filter_cb;
bmcb_data_filter.filter_userdata = filter_userdata;
if (bmtree->cos_cage) {
BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT));
}
hit.dist = dist;
hit.index = -1;
/* ok to leave 'uv' uninitialized */
bmcb_data->looptris = (const BMLoop *(*)[3])bmtree->looptris;
bmcb_data->cos_cage = (const float(*)[3])bmtree->cos_cage;
BLI_bvhtree_ray_cast(
bmtree->tree, co, dir, radius, &hit, bmbvh_ray_cast_cb_filter, &bmcb_data_filter);
if (hit.index != -1 && hit.dist != dist) {
return bmbvh_ray_cast_handle_hit(bmtree, bmcb_data, &hit, r_dist, r_hitout, r_cagehit);
}
return NULL;
}
/* -------------------------------------------------------------------- */
/* BKE_bmbvh_find_vert_closest */
struct VertSearchUserData {
/* from the bmtree */
const BMLoop *(*looptris)[3];
const float (*cos_cage)[3];
/* from the hit */
float dist_max_sq;
int index_tri;
};
static void bmbvh_find_vert_closest_cb(void *userdata,
int index,
const float co[3],
BVHTreeNearest *hit)
{
struct VertSearchUserData *bmcb_data = userdata;
const BMLoop **ltri = bmcb_data->looptris[index];
const float dist_max_sq = bmcb_data->dist_max_sq;
const float *tri_cos[3];
bmbvh_tri_from_face(tri_cos, ltri, bmcb_data->cos_cage);
for (int i = 0; i < 3; i++) {
const float dist_sq = len_squared_v3v3(co, tri_cos[i]);
if (dist_sq < hit->dist_sq && dist_sq < dist_max_sq) {
copy_v3_v3(hit->co, tri_cos[i]);
/* XXX, normal ignores cage */
copy_v3_v3(hit->no, ltri[i]->v->no);
hit->dist_sq = dist_sq;
hit->index = index;
bmcb_data->index_tri = i;
}
}
}
BMVert *BKE_bmbvh_find_vert_closest(BMBVHTree *bmtree, const float co[3], const float dist_max)
{
BVHTreeNearest hit;
struct VertSearchUserData bmcb_data;
const float dist_max_sq = dist_max * dist_max;
if (bmtree->cos_cage) {
BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT));
}
hit.dist_sq = dist_max_sq;
hit.index = -1;
bmcb_data.looptris = (const BMLoop *(*)[3])bmtree->looptris;
bmcb_data.cos_cage = (const float(*)[3])bmtree->cos_cage;
bmcb_data.dist_max_sq = dist_max_sq;
BLI_bvhtree_find_nearest(bmtree->tree, co, &hit, bmbvh_find_vert_closest_cb, &bmcb_data);
if (hit.index != -1) {
BMLoop **ltri = bmtree->looptris[hit.index];
return ltri[bmcb_data.index_tri]->v;
}
return NULL;
}
struct FaceSearchUserData {
/* from the bmtree */
const BMLoop *(*looptris)[3];
const float (*cos_cage)[3];
/* from the hit */
float dist_max_sq;
};
static void bmbvh_find_face_closest_cb(void *userdata,
int index,
const float co[3],
BVHTreeNearest *hit)
{
struct FaceSearchUserData *bmcb_data = userdata;
const BMLoop **ltri = bmcb_data->looptris[index];
const float dist_max_sq = bmcb_data->dist_max_sq;
const float *tri_cos[3];
bmbvh_tri_from_face(tri_cos, ltri, bmcb_data->cos_cage);
float co_close[3];
closest_on_tri_to_point_v3(co_close, co, UNPACK3(tri_cos));
const float dist_sq = len_squared_v3v3(co, co_close);
if (dist_sq < hit->dist_sq && dist_sq < dist_max_sq) {
/* XXX, normal ignores cage */
copy_v3_v3(hit->no, ltri[0]->f->no);
hit->dist_sq = dist_sq;
hit->index = index;
}
}
struct BMFace *BKE_bmbvh_find_face_closest(BMBVHTree *bmtree,
const float co[3],
const float dist_max)
{
BVHTreeNearest hit;
struct FaceSearchUserData bmcb_data;
const float dist_max_sq = dist_max * dist_max;
if (bmtree->cos_cage) {
BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT));
}
hit.dist_sq = dist_max_sq;
hit.index = -1;
bmcb_data.looptris = (const BMLoop *(*)[3])bmtree->looptris;
bmcb_data.cos_cage = (const float(*)[3])bmtree->cos_cage;
bmcb_data.dist_max_sq = dist_max_sq;
BLI_bvhtree_find_nearest(bmtree->tree, co, &hit, bmbvh_find_face_closest_cb, &bmcb_data);
if (hit.index != -1) {
BMLoop **ltri = bmtree->looptris[hit.index];
return ltri[0]->f;
}
return NULL;
}
/* -------------------------------------------------------------------- */
/* BKE_bmbvh_overlap */
struct BMBVHTree_OverlapData {
const BMBVHTree *tree_pair[2];
float epsilon;
};
static bool bmbvh_overlap_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
{
struct BMBVHTree_OverlapData *data = userdata;
const BMBVHTree *bmtree_a = data->tree_pair[0];
const BMBVHTree *bmtree_b = data->tree_pair[1];
BMLoop **tri_a = bmtree_a->looptris[index_a];
BMLoop **tri_b = bmtree_b->looptris[index_b];
const float *tri_a_co[3] = {tri_a[0]->v->co, tri_a[1]->v->co, tri_a[2]->v->co};
const float *tri_b_co[3] = {tri_b[0]->v->co, tri_b[1]->v->co, tri_b[2]->v->co};
float ix_pair[2][3];
int verts_shared = 0;
if (bmtree_a->looptris == bmtree_b->looptris) {
if (UNLIKELY(tri_a[0]->f == tri_b[0]->f)) {
return false;
}
verts_shared = (ELEM(tri_a_co[0], UNPACK3(tri_b_co)) + ELEM(tri_a_co[1], UNPACK3(tri_b_co)) +
ELEM(tri_a_co[2], UNPACK3(tri_b_co)));
/* if 2 points are shared, bail out */
if (verts_shared >= 2) {
return false;
}
}
return (isect_tri_tri_v3(UNPACK3(tri_a_co), UNPACK3(tri_b_co), ix_pair[0], ix_pair[1]) &&
/* if we share a vertex, check the intersection isn't a 'point' */
((verts_shared == 0) || (len_squared_v3v3(ix_pair[0], ix_pair[1]) > data->epsilon)));
}
BVHTreeOverlap *BKE_bmbvh_overlap(const BMBVHTree *bmtree_a,
const BMBVHTree *bmtree_b,
uint *r_overlap_tot)
{
struct BMBVHTree_OverlapData data;
data.tree_pair[0] = bmtree_a;
data.tree_pair[1] = bmtree_b;
data.epsilon = max_ff(BLI_bvhtree_get_epsilon(bmtree_a->tree),
BLI_bvhtree_get_epsilon(bmtree_b->tree));
return BLI_bvhtree_overlap(
bmtree_a->tree, bmtree_b->tree, r_overlap_tot, bmbvh_overlap_cb, &data);
}
static bool bmbvh_overlap_self_cb(void *userdata, int index_a, int index_b, int thread)
{
if (index_a < index_b) {
return bmbvh_overlap_cb(userdata, index_a, index_b, thread);
}
return false;
}
BVHTreeOverlap *BKE_bmbvh_overlap_self(const BMBVHTree *bmtree, uint *r_overlap_tot)
{
struct BMBVHTree_OverlapData data;
data.tree_pair[0] = bmtree;
data.tree_pair[1] = bmtree;
data.epsilon = BLI_bvhtree_get_epsilon(bmtree->tree);
return BLI_bvhtree_overlap(
bmtree->tree, bmtree->tree, r_overlap_tot, bmbvh_overlap_self_cb, &data);
}