Files
test2/intern/dualcon/intern/Projections.cpp

347 lines
8.4 KiB
C++

/* SPDX-FileCopyrightText: 2002-2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "Projections.h"
#include <cmath>
#include <algorithm>
const int vertmap[8][3] = {
{0, 0, 0},
{0, 0, 1},
{0, 1, 0},
{0, 1, 1},
{1, 0, 0},
{1, 0, 1},
{1, 1, 0},
{1, 1, 1},
};
const int centmap[3][3][3][2] = {
{{{0, 0}, {0, 1}, {1, 1}}, {{0, 2}, {0, 3}, {1, 3}}, {{2, 2}, {2, 3}, {3, 3}}},
{{{0, 4}, {0, 5}, {1, 5}}, {{0, 6}, {0, 7}, {1, 7}}, {{2, 6}, {2, 7}, {3, 7}}},
{{{4, 4}, {4, 5}, {5, 5}}, {{4, 6}, {4, 7}, {5, 7}}, {{6, 6}, {6, 7}, {7, 7}}}};
const int edgemap[12][2] = {
{0, 4},
{1, 5},
{2, 6},
{3, 7},
{0, 2},
{1, 3},
{4, 6},
{5, 7},
{0, 1},
{2, 3},
{4, 5},
{6, 7},
};
const int facemap[6][4] = {
{0, 1, 2, 3},
{4, 5, 6, 7},
{0, 1, 4, 5},
{2, 3, 6, 7},
{0, 2, 4, 6},
{1, 3, 5, 7},
};
/**
* Method to perform cross-product
*/
static void crossProduct(int64_t res[3], const int64_t a[3], const int64_t b[3])
{
res[0] = a[1] * b[2] - a[2] * b[1];
res[1] = a[2] * b[0] - a[0] * b[2];
res[2] = a[0] * b[1] - a[1] * b[0];
}
static void crossProduct(double res[3], const double a[3], const double b[3])
{
res[0] = a[1] * b[2] - a[2] * b[1];
res[1] = a[2] * b[0] - a[0] * b[2];
res[2] = a[0] * b[1] - a[1] * b[0];
}
/**
* Method to perform dot product
*/
static int64_t dotProduct(const int64_t a[3], const int64_t b[3])
{
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
static void normalize(double a[3])
{
double mag = a[0] * a[0] + a[1] * a[1] + a[2] * a[2];
if (mag > 0) {
mag = sqrt(mag);
a[0] /= mag;
a[1] /= mag;
a[2] /= mag;
}
}
/* Create projection axes for cube+triangle intersection testing.
* 0, 1, 2: cube face normals
*
* 3: triangle normal
*
* 4, 5, 6,
* 7, 8, 9,
* 10, 11, 12: cross of each triangle edge vector with each cube
* face normal
*/
static void create_projection_axes(int64_t axes[NUM_AXES][3], const int64_t tri[3][3])
{
/* Cube face normals */
axes[0][0] = 1;
axes[0][1] = 0;
axes[0][2] = 0;
axes[1][0] = 0;
axes[1][1] = 1;
axes[1][2] = 0;
axes[2][0] = 0;
axes[2][1] = 0;
axes[2][2] = 1;
/* Get triangle edge vectors */
int64_t tri_edges[3][3];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
tri_edges[i][j] = tri[(i + 1) % 3][j] - tri[i][j];
}
}
/* Triangle normal */
crossProduct(axes[3], tri_edges[0], tri_edges[1]);
// Face edges and triangle edges
int ct = 4;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
crossProduct(axes[ct], axes[j], tri_edges[i]);
ct++;
}
}
}
/**
* Construction from a cube (axes aligned) and triangle
*/
CubeTriangleIsect::CubeTriangleIsect(int64_t cube[2][3],
int64_t tri[3][3],
int64_t /*error*/,
int triind)
{
int i;
inherit = new TriangleProjection;
inherit->index = triind;
int64_t axes[NUM_AXES][3];
create_projection_axes(axes, tri);
/* Normalize face normal and store */
double dedge1[] = {(double)tri[1][0] - (double)tri[0][0],
(double)tri[1][1] - (double)tri[0][1],
(double)tri[1][2] - (double)tri[0][2]};
double dedge2[] = {(double)tri[2][0] - (double)tri[1][0],
(double)tri[2][1] - (double)tri[1][1],
(double)tri[2][2] - (double)tri[1][2]};
crossProduct(inherit->norm, dedge1, dedge2);
normalize(inherit->norm);
int64_t cubeedge[3][3];
for (i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
cubeedge[i][j] = 0;
}
cubeedge[i][i] = cube[1][i] - cube[0][i];
}
/* Project the cube on to each axis */
for (int axis = 0; axis < NUM_AXES; axis++) {
CubeProjection &cube_proj = cubeProj[axis];
/* Origin */
cube_proj.origin = dotProduct(axes[axis], cube[0]);
/* 3 direction vectors */
for (i = 0; i < 3; i++) {
cube_proj.edges[i] = dotProduct(axes[axis], cubeedge[i]);
}
/* Offsets of 2 ends of cube projection */
int64_t max = 0;
int64_t min = 0;
for (i = 1; i < 8; i++) {
int64_t proj = (vertmap[i][0] * cube_proj.edges[0] + vertmap[i][1] * cube_proj.edges[1] +
vertmap[i][2] * cube_proj.edges[2]);
max = std::max(proj, max);
min = std::min(proj, min);
}
cube_proj.min = min;
cube_proj.max = max;
}
/* Project the triangle on to each axis */
for (int axis = 0; axis < NUM_AXES; axis++) {
const int64_t vts[3] = {dotProduct(axes[axis], tri[0]),
dotProduct(axes[axis], tri[1]),
dotProduct(axes[axis], tri[2])};
// Triangle
inherit->tri_proj[axis][0] = vts[0];
inherit->tri_proj[axis][1] = vts[0];
for (i = 1; i < 3; i++) {
inherit->tri_proj[axis][0] = std::min(vts[i], inherit->tri_proj[axis][0]);
inherit->tri_proj[axis][1] = std::max(vts[i], inherit->tri_proj[axis][1]);
}
}
}
/**
* Construction
* from a parent CubeTriangleIsect object and the index of the children
*/
CubeTriangleIsect::CubeTriangleIsect(CubeTriangleIsect *parent)
{
// Copy inheritable projections
this->inherit = parent->inherit;
// Shrink cube projections
for (int i = 0; i < NUM_AXES; i++) {
cubeProj[i].origin = parent->cubeProj[i].origin;
for (int j = 0; j < 3; j++) {
cubeProj[i].edges[j] = parent->cubeProj[i].edges[j] >> 1;
}
cubeProj[i].min = parent->cubeProj[i].min >> 1;
cubeProj[i].max = parent->cubeProj[i].max >> 1;
}
}
unsigned char CubeTriangleIsect::getBoxMask()
{
int i, j, k;
int bmask[3][2] = {{0, 0}, {0, 0}, {0, 0}};
unsigned char boxmask = 0;
int64_t child_len = cubeProj[0].edges[0] >> 1;
for (i = 0; i < 3; i++) {
int64_t mid = cubeProj[i].origin + child_len;
// Check bounding box
if (mid >= inherit->tri_proj[i][0]) {
bmask[i][0] = 1;
}
if (mid < inherit->tri_proj[i][1]) {
bmask[i][1] = 1;
}
}
// Fill in masks
int ct = 0;
for (i = 0; i < 2; i++) {
for (j = 0; j < 2; j++) {
for (k = 0; k < 2; k++) {
boxmask |= ((bmask[0][i] & bmask[1][j] & bmask[2][k]) << ct);
ct++;
}
}
}
// Return bounding box masks
return boxmask;
}
/**
* Shifting a cube to a new origin
*/
void CubeTriangleIsect::shift(const int off[3])
{
for (int i = 0; i < NUM_AXES; i++) {
cubeProj[i].origin += (off[0] * cubeProj[i].edges[0] + off[1] * cubeProj[i].edges[1] +
off[2] * cubeProj[i].edges[2]);
}
}
/**
* Method to test intersection of the triangle and the cube
*/
int CubeTriangleIsect::isIntersecting() const
{
for (int i = 0; i < NUM_AXES; i++) {
/*
int64_t proj0 = cubeProj[i][0] +
vertmap[inherit->cubeEnds[i][0]][0] * cubeProj[i][1] +
vertmap[inherit->cubeEnds[i][0]][1] * cubeProj[i][2] +
vertmap[inherit->cubeEnds[i][0]][2] * cubeProj[i][3] ;
int64_t proj1 = cubeProj[i][0] +
vertmap[inherit->cubeEnds[i][1]][0] * cubeProj[i][1] +
vertmap[inherit->cubeEnds[i][1]][1] * cubeProj[i][2] +
vertmap[inherit->cubeEnds[i][1]][2] * cubeProj[i][3] ;
*/
int64_t proj0 = cubeProj[i].origin + cubeProj[i].min;
int64_t proj1 = cubeProj[i].origin + cubeProj[i].max;
if (proj0 > inherit->tri_proj[i][1] || proj1 < inherit->tri_proj[i][0]) {
return 0;
}
}
return 1;
}
int CubeTriangleIsect::isIntersectingPrimary(int edgeInd) const
{
for (int i = 0; i < NUM_AXES; i++) {
int64_t proj0 = cubeProj[i].origin;
int64_t proj1 = cubeProj[i].origin + cubeProj[i].edges[edgeInd];
if (proj0 < proj1) {
if (proj0 > inherit->tri_proj[i][1] || proj1 < inherit->tri_proj[i][0]) {
return 0;
}
}
else {
if (proj1 > inherit->tri_proj[i][1] || proj0 < inherit->tri_proj[i][0]) {
return 0;
}
}
}
// printf( "Intersecting: %d %d\n", edgemap[edgeInd][0], edgemap[edgeInd][1] ) ;
return 1;
}
float CubeTriangleIsect::getIntersectionPrimary(int edgeInd) const
{
int i = 3;
int64_t proj0 = cubeProj[i].origin;
int64_t proj1 = cubeProj[i].origin + cubeProj[i].edges[edgeInd];
int64_t proj2 = inherit->tri_proj[i][1];
int64_t d = proj1 - proj0;
double alpha;
if (d == 0) {
alpha = 0.5;
}
else {
alpha = (double)((proj2 - proj0)) / (double)d;
if (alpha < 0 || alpha > 1) {
alpha = 0.5;
}
}
return (float)alpha;
}