Files
test/source/blender/freestyle/intern/geometry/GeomUtils.cpp
Campbell Barton e955c94ed3 License Headers: Set copyright to "Blender Authors", add AUTHORS
Listing the "Blender Foundation" as copyright holder implied the Blender
Foundation holds copyright to files which may include work from many
developers.

While keeping copyright on headers makes sense for isolated libraries,
Blender's own code may be refactored or moved between files in a way
that makes the per file copyright holders less meaningful.

Copyright references to the "Blender Foundation" have been replaced with
"Blender Authors", with the exception of `./extern/` since these this
contains libraries which are more isolated, any changed to license
headers there can be handled on a case-by-case basis.

Some directories in `./intern/` have also been excluded:

- `./intern/cycles/` it's own `AUTHORS` file is planned.
- `./intern/opensubdiv/`.

An "AUTHORS" file has been added, using the chromium projects authors
file as a template.

Design task: #110784

Ref !110783.
2023-08-16 00:20:26 +10:00

839 lines
21 KiB
C++

/* SPDX-FileCopyrightText: 2009-2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup freestyle
* \brief Various tools for geometry
*/
#include "GeomUtils.h"
#include "BLI_sys_types.h"
namespace Freestyle::GeomUtils {
// This internal procedure is defined below.
bool intersect2dSegPoly(Vec2r *seg, Vec2r *poly, uint n);
bool intersect2dSeg2dArea(const Vec2r &min, const Vec2r &max, const Vec2r &A, const Vec2r &B)
{
Vec2r seg[2];
seg[0] = A;
seg[1] = B;
Vec2r poly[5];
poly[0][0] = min[0];
poly[0][1] = min[1];
poly[1][0] = max[0];
poly[1][1] = min[1];
poly[2][0] = max[0];
poly[2][1] = max[1];
poly[3][0] = min[0];
poly[3][1] = max[1];
poly[4][0] = min[0];
poly[4][1] = min[1];
return intersect2dSegPoly(seg, poly, 4);
}
bool include2dSeg2dArea(const Vec2r &min, const Vec2r &max, const Vec2r &A, const Vec2r &B)
{
if ((((max[0] > A[0]) && (A[0] > min[0])) && ((max[0] > B[0]) && (B[0] > min[0]))) &&
(((max[1] > A[1]) && (A[1] > min[1])) && ((max[1] > B[1]) && (B[1] > min[1]))))
{
return true;
}
return false;
}
intersection_test intersect2dSeg2dSeg(
const Vec2r &p1, const Vec2r &p2, const Vec2r &p3, const Vec2r &p4, Vec2r &res)
{
real a1, a2, b1, b2, c1, c2; // Coefficients of line eqns
real r1, r2, r3, r4; // 'Sign' values
real denom, num; // Intermediate values
// Compute a1, b1, c1, where line joining points p1 and p2 is "a1 x + b1 y + c1 = 0".
a1 = p2[1] - p1[1];
b1 = p1[0] - p2[0];
c1 = p2[0] * p1[1] - p1[0] * p2[1];
// Compute r3 and r4.
r3 = a1 * p3[0] + b1 * p3[1] + c1;
r4 = a1 * p4[0] + b1 * p4[1] + c1;
// Check signs of r3 and r4. If both point 3 and point 4 lie on same side of line 1,
// the line segments do not intersect.
if (r3 != 0 && r4 != 0 && r3 * r4 > 0.0) {
return DONT_INTERSECT;
}
// Compute a2, b2, c2
a2 = p4[1] - p3[1];
b2 = p3[0] - p4[0];
c2 = p4[0] * p3[1] - p3[0] * p4[1];
// Compute r1 and r2
r1 = a2 * p1[0] + b2 * p1[1] + c2;
r2 = a2 * p2[0] + b2 * p2[1] + c2;
// Check signs of r1 and r2. If both point 1 and point 2 lie on same side of second line
// segment, the line segments do not intersect.
if (r1 != 0 && r2 != 0 && r1 * r2 > 0.0) {
return DONT_INTERSECT;
}
// Line segments intersect: compute intersection point.
denom = a1 * b2 - a2 * b1;
if (fabs(denom) < M_EPSILON) {
return COLINEAR;
}
num = b1 * c2 - b2 * c1;
res[0] = num / denom;
num = a2 * c1 - a1 * c2;
res[1] = num / denom;
return DO_INTERSECT;
}
intersection_test intersect2dLine2dLine(
const Vec2r &p1, const Vec2r &p2, const Vec2r &p3, const Vec2r &p4, Vec2r &res)
{
real a1, a2, b1, b2, c1, c2; // Coefficients of line eqns
real denom, num; // Intermediate values
// Compute a1, b1, c1, where line joining points p1 and p2 is "a1 x + b1 y + c1 = 0".
a1 = p2[1] - p1[1];
b1 = p1[0] - p2[0];
c1 = p2[0] * p1[1] - p1[0] * p2[1];
// Compute a2, b2, c2
a2 = p4[1] - p3[1];
b2 = p3[0] - p4[0];
c2 = p4[0] * p3[1] - p3[0] * p4[1];
// Line segments intersect: compute intersection point.
denom = a1 * b2 - a2 * b1;
if (fabs(denom) < M_EPSILON) {
return COLINEAR;
}
num = b1 * c2 - b2 * c1;
res[0] = num / denom;
num = a2 * c1 - a1 * c2;
res[1] = num / denom;
return DO_INTERSECT;
}
intersection_test intersect2dSeg2dSegParametric(const Vec2r &p1,
const Vec2r &p2,
const Vec2r &p3,
const Vec2r &p4,
real &t,
real &u,
real epsilon)
{
real a1, a2, b1, b2, c1, c2; // Coefficients of line eqns
real r1, r2, r3, r4; // 'Sign' values
real denom, num; // Intermediate values
// Compute a1, b1, c1, where line joining points p1 and p2 is "a1 x + b1 y + c1 = 0".
a1 = p2[1] - p1[1];
b1 = p1[0] - p2[0];
c1 = p2[0] * p1[1] - p1[0] * p2[1];
// Compute r3 and r4.
r3 = a1 * p3[0] + b1 * p3[1] + c1;
r4 = a1 * p4[0] + b1 * p4[1] + c1;
// Check signs of r3 and r4. If both point 3 and point 4 lie on same side of line 1,
// the line segments do not intersect.
if (r3 != 0 && r4 != 0 && r3 * r4 > 0.0) {
return DONT_INTERSECT;
}
// Compute a2, b2, c2
a2 = p4[1] - p3[1];
b2 = p3[0] - p4[0];
c2 = p4[0] * p3[1] - p3[0] * p4[1];
// Compute r1 and r2
r1 = a2 * p1[0] + b2 * p1[1] + c2;
r2 = a2 * p2[0] + b2 * p2[1] + c2;
// Check signs of r1 and r2. If both point 1 and point 2 lie on same side of second line
// segment, the line segments do not intersect.
if (r1 != 0 && r2 != 0 && r1 * r2 > 0.0) {
return DONT_INTERSECT;
}
// Line segments intersect: compute intersection point.
denom = a1 * b2 - a2 * b1;
if (fabs(denom) < epsilon) {
return COLINEAR;
}
real d1, e1;
d1 = p1[1] - p3[1];
e1 = p1[0] - p3[0];
num = -b2 * d1 - a2 * e1;
t = num / denom;
num = -b1 * d1 - a1 * e1;
u = num / denom;
return DO_INTERSECT;
}
// AABB-triangle overlap test code by Tomas Akenine-Möller
// Function: int triBoxOverlap(real boxcenter[3], real boxhalfsize[3],real triverts[3][3]);
// History:
// 2001-03-05: released the code in its first version
// 2001-06-18: changed the order of the tests, faster
//
// Acknowledgement: Many thanks to Pierre Terdiman for suggestions and discussions on how to
// optimize code. Thanks to David Hunt for finding a ">="-bug!
#define X 0
#define Y 1
#define Z 2
#define FINDMINMAX(x0, x1, x2, min, max) \
{ \
min = max = x0; \
if (x1 < min) { \
min = x1; \
} \
if (x1 > max) { \
max = x1; \
} \
if (x2 < min) { \
min = x2; \
} \
if (x2 > max) { \
max = x2; \
} \
} \
(void)0
//======================== X-tests ========================//
#define AXISTEST_X01(a, b, fa, fb) \
{ \
p0 = a * v0[Y] - b * v0[Z]; \
p2 = a * v2[Y] - b * v2[Z]; \
if (p0 < p2) { \
min = p0; \
max = p2; \
} \
else { \
min = p2; \
max = p0; \
} \
rad = fa * boxhalfsize[Y] + fb * boxhalfsize[Z]; \
if (min > rad || max < -rad) { \
return 0; \
} \
} \
(void)0
#define AXISTEST_X2(a, b, fa, fb) \
{ \
p0 = a * v0[Y] - b * v0[Z]; \
p1 = a * v1[Y] - b * v1[Z]; \
if (p0 < p1) { \
min = p0; \
max = p1; \
} \
else { \
min = p1; \
max = p0; \
} \
rad = fa * boxhalfsize[Y] + fb * boxhalfsize[Z]; \
if (min > rad || max < -rad) { \
return 0; \
} \
} \
(void)0
//======================== Y-tests ========================//
#define AXISTEST_Y02(a, b, fa, fb) \
{ \
p0 = -a * v0[X] + b * v0[Z]; \
p2 = -a * v2[X] + b * v2[Z]; \
if (p0 < p2) { \
min = p0; \
max = p2; \
} \
else { \
min = p2; \
max = p0; \
} \
rad = fa * boxhalfsize[X] + fb * boxhalfsize[Z]; \
if (min > rad || max < -rad) { \
return 0; \
} \
} \
(void)0
#define AXISTEST_Y1(a, b, fa, fb) \
{ \
p0 = -a * v0[X] + b * v0[Z]; \
p1 = -a * v1[X] + b * v1[Z]; \
if (p0 < p1) { \
min = p0; \
max = p1; \
} \
else { \
min = p1; \
max = p0; \
} \
rad = fa * boxhalfsize[X] + fb * boxhalfsize[Z]; \
if (min > rad || max < -rad) { \
return 0; \
} \
} \
(void)0
//======================== Z-tests ========================//
#define AXISTEST_Z12(a, b, fa, fb) \
{ \
p1 = a * v1[X] - b * v1[Y]; \
p2 = a * v2[X] - b * v2[Y]; \
if (p2 < p1) { \
min = p2; \
max = p1; \
} \
else { \
min = p1; \
max = p2; \
} \
rad = fa * boxhalfsize[X] + fb * boxhalfsize[Y]; \
if (min > rad || max < -rad) { \
return 0; \
} \
} \
(void)0
#define AXISTEST_Z0(a, b, fa, fb) \
{ \
p0 = a * v0[X] - b * v0[Y]; \
p1 = a * v1[X] - b * v1[Y]; \
if (p0 < p1) { \
min = p0; \
max = p1; \
} \
else { \
min = p1; \
max = p0; \
} \
rad = fa * boxhalfsize[X] + fb * boxhalfsize[Y]; \
if (min > rad || max < -rad) { \
return 0; \
} \
} \
(void)0
// This internal procedure is defined below.
bool overlapPlaneBox(Vec3r &normal, real d, Vec3r &maxbox);
// Use separating axis theorem to test overlap between triangle and box need to test for overlap in
// these directions: 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle we
// do not even need to test these) 2) normal of the triangle 3) crossproduct(edge from tri,
// {x,y,z}-directin) this gives 3x3=9 more tests
bool overlapTriangleBox(Vec3r &boxcenter, Vec3r &boxhalfsize, Vec3r triverts[3])
{
Vec3r v0, v1, v2, normal, e0, e1, e2;
real min, max, d, p0, p1, p2, rad, fex, fey, fez;
// This is the fastest branch on Sun
// move everything so that the boxcenter is in (0, 0, 0)
v0 = triverts[0] - boxcenter;
v1 = triverts[1] - boxcenter;
v2 = triverts[2] - boxcenter;
// compute triangle edges
e0 = v1 - v0;
e1 = v2 - v1;
e2 = v0 - v2;
// Bullet 3:
// Do the 9 tests first (this was faster)
fex = fabs(e0[X]);
fey = fabs(e0[Y]);
fez = fabs(e0[Z]);
AXISTEST_X01(e0[Z], e0[Y], fez, fey);
AXISTEST_Y02(e0[Z], e0[X], fez, fex);
AXISTEST_Z12(e0[Y], e0[X], fey, fex);
fex = fabs(e1[X]);
fey = fabs(e1[Y]);
fez = fabs(e1[Z]);
AXISTEST_X01(e1[Z], e1[Y], fez, fey);
AXISTEST_Y02(e1[Z], e1[X], fez, fex);
AXISTEST_Z0(e1[Y], e1[X], fey, fex);
fex = fabs(e2[X]);
fey = fabs(e2[Y]);
fez = fabs(e2[Z]);
AXISTEST_X2(e2[Z], e2[Y], fez, fey);
AXISTEST_Y1(e2[Z], e2[X], fez, fex);
AXISTEST_Z12(e2[Y], e2[X], fey, fex);
// Bullet 1:
// first test overlap in the {x,y,z}-directions
// find min, max of the triangle each direction, and test for overlap in that direction -- this
// is equivalent to testing a minimal AABB around the triangle against the AABB
// test in X-direction
FINDMINMAX(v0[X], v1[X], v2[X], min, max);
if (min > boxhalfsize[X] || max < -boxhalfsize[X]) {
return false;
}
// test in Y-direction
FINDMINMAX(v0[Y], v1[Y], v2[Y], min, max);
if (min > boxhalfsize[Y] || max < -boxhalfsize[Y]) {
return false;
}
// test in Z-direction
FINDMINMAX(v0[Z], v1[Z], v2[Z], min, max);
if (min > boxhalfsize[Z] || max < -boxhalfsize[Z]) {
return false;
}
// Bullet 2:
// test if the box intersects the plane of the triangle
// compute plane equation of triangle: normal * x + d = 0
normal = e0 ^ e1;
d = -(normal * v0); // plane eq: normal.x + d = 0
if (!overlapPlaneBox(normal, d, boxhalfsize)) {
return false;
}
return true; // box and triangle overlaps
}
// Fast, Minimum Storage Ray-Triangle Intersection
//
// Tomas Möller
// Prosolvia Clarus AB
// Sweden
// <tompa@clarus.se>
//
// Ben Trumbore
// Cornell University
// Ithaca, New York
// <wbt@graphics.cornell.edu>
bool intersectRayTriangle(const Vec3r &orig,
const Vec3r &dir,
const Vec3r &v0,
const Vec3r &v1,
const Vec3r &v2,
real &t,
real &u,
real &v,
const real epsilon)
{
Vec3r edge1, edge2, tvec, pvec, qvec;
real det, inv_det;
// find vectors for two edges sharing v0
edge1 = v1 - v0;
edge2 = v2 - v0;
// begin calculating determinant - also used to calculate U parameter
pvec = dir ^ edge2;
// if determinant is near zero, ray lies in plane of triangle
det = edge1 * pvec;
// calculate distance from v0 to ray origin
tvec = orig - v0;
inv_det = 1.0 / det;
qvec = tvec ^ edge1;
if (det > epsilon) {
u = tvec * pvec;
if (u < 0.0 || u > det) {
return false;
}
// calculate V parameter and test bounds
v = dir * qvec;
if (v < 0.0 || u + v > det) {
return false;
}
}
else if (det < -epsilon) {
// calculate U parameter and test bounds
u = tvec * pvec;
if (u > 0.0 || u < det) {
return false;
}
// calculate V parameter and test bounds
v = dir * qvec;
if (v > 0.0 || u + v < det) {
return false;
}
}
else {
return false; // ray is parallel to the plane of the triangle
}
u *= inv_det;
v *= inv_det;
t = (edge2 * qvec) * inv_det;
return true;
}
// Intersection between plane and ray, adapted from Graphics Gems, Didier Badouel
// The plane is represented by a set of points P implicitly defined as dot(norm, P) + d = 0.
// The ray is represented as r(t) = orig + dir * t.
intersection_test intersectRayPlane(const Vec3r &orig,
const Vec3r &dir,
const Vec3r &norm,
const real d,
real &t,
const real epsilon)
{
real denom = norm * dir;
if (fabs(denom) <= epsilon) { // plane and ray are parallel
if (fabs((norm * orig) + d) <= epsilon) {
return COINCIDENT; // plane and ray are coincident
}
return COLINEAR;
}
t = -(d + (norm * orig)) / denom;
if (t < 0.0f) {
return DONT_INTERSECT;
}
return DO_INTERSECT;
}
bool intersectRayBBox(const Vec3r &orig,
const Vec3r &dir, // ray origin and direction
const Vec3r &boxMin,
const Vec3r &boxMax, // the bbox
real t0,
real t1,
real &tmin, // I0 = orig + tmin * dir is the first intersection
real &tmax, // I1 = orig + tmax * dir is the second intersection
real /*epsilon*/)
{
float tymin, tymax, tzmin, tzmax;
Vec3r inv_direction(1.0 / dir[0], 1.0 / dir[1], 1.0 / dir[2]);
int sign[3];
sign[0] = (inv_direction.x() < 0);
sign[1] = (inv_direction.y() < 0);
sign[2] = (inv_direction.z() < 0);
Vec3r bounds[2];
bounds[0] = boxMin;
bounds[1] = boxMax;
tmin = (bounds[sign[0]].x() - orig.x()) * inv_direction.x();
tmax = (bounds[1 - sign[0]].x() - orig.x()) * inv_direction.x();
tymin = (bounds[sign[1]].y() - orig.y()) * inv_direction.y();
tymax = (bounds[1 - sign[1]].y() - orig.y()) * inv_direction.y();
if ((tmin > tymax) || (tymin > tmax)) {
return false;
}
if (tymin > tmin) {
tmin = tymin;
}
if (tymax < tmax) {
tmax = tymax;
}
tzmin = (bounds[sign[2]].z() - orig.z()) * inv_direction.z();
tzmax = (bounds[1 - sign[2]].z() - orig.z()) * inv_direction.z();
if ((tmin > tzmax) || (tzmin > tmax)) {
return false;
}
if (tzmin > tmin) {
tmin = tzmin;
}
if (tzmax < tmax) {
tmax = tzmax;
}
return ((tmin < t1) && (tmax > t0));
}
// Checks whether 3D points p lies inside or outside of the triangle ABC
bool includePointTriangle(const Vec3r &P, const Vec3r &A, const Vec3r &B, const Vec3r &C)
{
Vec3r AB(B - A);
Vec3r BC(C - B);
Vec3r CA(A - C);
Vec3r AP(P - A);
Vec3r BP(P - B);
Vec3r CP(P - C);
Vec3r N(AB ^ BC); // triangle's normal
N.normalize();
Vec3r J(AB ^ AP), K(BC ^ BP), L(CA ^ CP);
J.normalize();
K.normalize();
L.normalize();
if (J * N < 0) {
return false; // on the right of AB
}
if (K * N < 0) {
return false; // on the right of BC
}
if (L * N < 0) {
return false; // on the right of CA
}
return true;
}
void transformVertex(const Vec3r &vert, const Matrix44r &matrix, Vec3r &res)
{
HVec3r hvert(vert), res_tmp;
real scale;
for (uint j = 0; j < 4; j++) {
scale = hvert[j];
for (uint i = 0; i < 4; i++) {
res_tmp[i] += matrix(i, j) * scale;
}
}
res[0] = res_tmp.x();
res[1] = res_tmp.y();
res[2] = res_tmp.z();
}
void transformVertices(const vector<Vec3r> &vertices, const Matrix44r &trans, vector<Vec3r> &res)
{
size_t i;
res.resize(vertices.size());
for (i = 0; i < vertices.size(); i++) {
transformVertex(vertices[i], trans, res[i]);
}
}
Vec3r rotateVector(const Matrix44r &mat, const Vec3r &v)
{
Vec3r res;
for (uint i = 0; i < 3; i++) {
res[i] = 0;
for (uint j = 0; j < 3; j++) {
res[i] += mat(i, j) * v[j];
}
}
res.normalize();
return res;
}
// This internal procedure is defined below.
void fromCoordAToCoordB(const Vec3r &p, Vec3r &q, const real transform[4][4]);
void fromWorldToCamera(const Vec3r &p, Vec3r &q, const real model_view_matrix[4][4])
{
fromCoordAToCoordB(p, q, model_view_matrix);
}
void fromCameraToRetina(const Vec3r &p, Vec3r &q, const real projection_matrix[4][4])
{
fromCoordAToCoordB(p, q, projection_matrix);
}
void fromRetinaToImage(const Vec3r &p, Vec3r &q, const int viewport[4])
{
// winX:
q[0] = viewport[0] + viewport[2] * (p[0] + 1.0) / 2.0;
// winY:
q[1] = viewport[1] + viewport[3] * (p[1] + 1.0) / 2.0;
// winZ:
q[2] = (p[2] + 1.0) / 2.0;
}
void fromWorldToImage(const Vec3r &p,
Vec3r &q,
const real model_view_matrix[4][4],
const real projection_matrix[4][4],
const int viewport[4])
{
Vec3r p1, p2;
fromWorldToCamera(p, p1, model_view_matrix);
fromCameraToRetina(p1, p2, projection_matrix);
fromRetinaToImage(p2, q, viewport);
q[2] = p1[2];
}
void fromWorldToImage(const Vec3r &p, Vec3r &q, const real transform[4][4], const int viewport[4])
{
fromCoordAToCoordB(p, q, transform);
// winX:
q[0] = viewport[0] + viewport[2] * (q[0] + 1.0) / 2.0;
// winY:
q[1] = viewport[1] + viewport[3] * (q[1] + 1.0) / 2.0;
}
void fromImageToRetina(const Vec3r &p, Vec3r &q, const int viewport[4])
{
q = p;
q[0] = 2.0 * (q[0] - viewport[0]) / viewport[2] - 1.0;
q[1] = 2.0 * (q[1] - viewport[1]) / viewport[3] - 1.0;
}
void fromRetinaToCamera(const Vec3r &p, Vec3r &q, real focal, const real projection_matrix[4][4])
{
if (projection_matrix[3][3] == 0.0) { // perspective
q[0] = (-p[0] * focal) / projection_matrix[0][0];
q[1] = (-p[1] * focal) / projection_matrix[1][1];
q[2] = focal;
}
else { // orthogonal
q[0] = p[0] / projection_matrix[0][0];
q[1] = p[1] / projection_matrix[1][1];
q[2] = focal;
}
}
void fromCameraToWorld(const Vec3r &p, Vec3r &q, const real model_view_matrix[4][4])
{
real translation[3] = {
model_view_matrix[0][3],
model_view_matrix[1][3],
model_view_matrix[2][3],
};
for (ushort i = 0; i < 3; i++) {
q[i] = 0.0;
for (ushort j = 0; j < 3; j++) {
q[i] += model_view_matrix[j][i] * (p[j] - translation[j]);
}
}
}
//
// Internal code
//
/////////////////////////////////////////////////////////////////////////////
// Copyright 2001, softSurfer (www.softsurfer.com)
// This code may be freely used and modified for any purpose providing that this copyright notice
// is included with it. SoftSurfer makes no warranty for this code, and cannot be held liable for
// any real or imagined damage resulting from its use. Users of this code must verify correctness
// for their application.
#define PERP(u, v) ((u)[0] * (v)[1] - (u)[1] * (v)[0]) // 2D perp product
inline bool intersect2dSegPoly(Vec2r *seg, Vec2r *poly, uint n)
{
if (seg[0] == seg[1]) {
return false;
}
real tE = 0; // the maximum entering segment parameter
real tL = 1; // the minimum leaving segment parameter
real t, N, D; // intersect parameter t = N / D
Vec2r dseg = seg[1] - seg[0]; // the segment direction vector
Vec2r e; // edge vector
for (uint i = 0; i < n; i++) { // process polygon edge poly[i]poly[i+1]
e = poly[i + 1] - poly[i];
N = PERP(e, seg[0] - poly[i]);
D = -PERP(e, dseg);
if (fabs(D) < M_EPSILON) {
if (N < 0) {
return false;
}
continue;
}
t = N / D;
if (D < 0) { // segment seg is entering across this edge
if (t > tE) { // new max tE
tE = t;
if (tE > tL) { // seg enters after leaving polygon
return false;
}
}
}
else { // segment seg is leaving across this edge
if (t < tL) { // new min tL
tL = t;
if (tL < tE) { // seg leaves before entering polygon
return false;
}
}
}
}
// tE <= tL implies that there is a valid intersection subsegment
return true;
}
inline bool overlapPlaneBox(Vec3r &normal, real d, Vec3r &maxbox)
{
Vec3r vmin, vmax;
for (uint q = X; q <= Z; q++) {
if (normal[q] > 0.0f) {
vmin[q] = -maxbox[q];
vmax[q] = maxbox[q];
}
else {
vmin[q] = maxbox[q];
vmax[q] = -maxbox[q];
}
}
if ((normal * vmin) + d > 0.0f) {
return false;
}
if ((normal * vmax) + d >= 0.0f) {
return true;
}
return false;
}
inline void fromCoordAToCoordB(const Vec3r &p, Vec3r &q, const real transform[4][4])
{
HVec3r hp(p);
HVec3r hq(0, 0, 0, 0);
for (uint i = 0; i < 4; i++) {
for (uint j = 0; j < 4; j++) {
hq[i] += transform[i][j] * hp[j];
}
}
if (hq[3] == 0) {
q = p;
return;
}
for (uint k = 0; k < 3; k++) {
q[k] = hq[k] / hq[3];
}
}
} // namespace Freestyle::GeomUtils