Files
test/source/blender/freestyle/intern/geometry/GridHelpers.h
Campbell Barton c434782e3a File headers: SPDX License migration
Use a shorter/simpler license convention, stops the header taking so
much space.

Follow the SPDX license specification: https://spdx.org/licenses

- C/C++/objc/objc++
- Python
- Shell Scripts
- CMake, GNUmakefile

While most of the source tree has been included

- `./extern/` was left out.
- `./intern/cycles` & `./intern/atomic` are also excluded because they
  use different header conventions.

doc/license/SPDX-license-identifiers.txt has been added to list SPDX all
used identifiers.

See P2788 for the script that automated these edits.

Reviewed By: brecht, mont29, sergey

Ref D14069
2022-02-11 09:14:36 +11:00

200 lines
5.3 KiB
C++

/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
/** \file
* \ingroup freestyle
* \brief Class to define a cell grid surrounding the projected image of a scene
*/
#include <vector>
#include "FRS_freestyle.h"
#include "GeomUtils.h"
#include "Polygon.h"
#include "../winged_edge/WEdge.h"
#ifdef WITH_CXX_GUARDEDALLOC
# include "MEM_guardedalloc.h"
#endif
namespace Freestyle {
namespace GridHelpers {
/** Computes the distance from a point P to a segment AB */
template<class T> T closestPointToSegment(const T &P, const T &A, const T &B, real &distance)
{
T AB, AP, BP;
AB = B - A;
AP = P - A;
BP = P - B;
real c1(AB * AP);
if (c1 <= 0) {
distance = AP.norm();
return A; // A is closest point
}
real c2(AB * AB);
if (c2 <= c1) {
distance = BP.norm();
return B; // B is closest point
}
real b = c1 / c2;
T Pb, PPb;
Pb = A + b * AB;
PPb = P - Pb;
distance = PPb.norm();
return Pb; // closest point lies on AB
}
inline Vec3r closestPointOnPolygon(const Vec3r &point, const Polygon3r &poly)
{
// First cast a ray from the point onto the polygon plane
// If the ray intersects the polygon, then the intersection point
// is the closest point on the polygon
real t, u, v;
if (poly.rayIntersect(point, poly.getNormal(), t, u, v)) {
return point + poly.getNormal() * t;
}
// Otherwise, get the nearest point on each edge, and take the closest
real distance;
Vec3r closest = closestPointToSegment(
point, poly.getVertices()[2], poly.getVertices()[0], distance);
for (unsigned int i = 0; i < 2; ++i) {
real t;
Vec3r p = closestPointToSegment(point, poly.getVertices()[i], poly.getVertices()[i + 1], t);
if (t < distance) {
distance = t;
closest = p;
}
}
return closest;
}
inline real distancePointToPolygon(const Vec3r &point, const Polygon3r &poly)
{
// First cast a ray from the point onto the polygon plane
// If the ray intersects the polygon, then the intersection point
// is the closest point on the polygon
real t, u, v;
if (poly.rayIntersect(point, poly.getNormal(), t, u, v)) {
return (t > 0.0) ? t : -t;
}
// Otherwise, get the nearest point on each edge, and take the closest
real distance = GeomUtils::distPointSegment(point, poly.getVertices()[2], poly.getVertices()[0]);
for (unsigned int i = 0; i < 2; ++i) {
real t = GeomUtils::distPointSegment(point, poly.getVertices()[i], poly.getVertices()[i + 1]);
if (t < distance) {
distance = t;
}
}
return distance;
}
class Transform {
public:
virtual ~Transform() = 0;
virtual Vec3r operator()(const Vec3r &point) const = 0;
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:GridHelpers:Transform")
#endif
};
inline bool insideProscenium(const real proscenium[4], const Polygon3r &polygon)
{
// N.B. The bounding box check is redundant for inserting occluders into cells, because the cell
// selection code in insertOccluders has already guaranteed that the bounding boxes will overlap.
// First check the viewport edges, since they are the easiest case
// Check if the bounding box is entirely outside the proscenium
Vec3r bbMin, bbMax;
polygon.getBBox(bbMin, bbMax);
if (bbMax[0] < proscenium[0] || bbMin[0] > proscenium[1] || bbMax[1] < proscenium[2] ||
bbMin[1] > proscenium[3]) {
return false;
}
Vec3r boxCenter(proscenium[0] + (proscenium[1] - proscenium[0]) / 2.0,
proscenium[2] + (proscenium[3] - proscenium[2]) / 2.0,
0.0);
Vec3r boxHalfSize(
(proscenium[1] - proscenium[0]) / 2.0, (proscenium[3] - proscenium[2]) / 2.0, 1.0);
Vec3r triverts[3] = {
Vec3r(polygon.getVertices()[0][0], polygon.getVertices()[0][1], 0.0),
Vec3r(polygon.getVertices()[1][0], polygon.getVertices()[1][1], 0.0),
Vec3r(polygon.getVertices()[2][0], polygon.getVertices()[2][1], 0.0),
};
return GeomUtils::overlapTriangleBox(boxCenter, boxHalfSize, triverts);
}
inline vector<Vec3r> enumerateVertices(const vector<WOEdge *> &fedges)
{
vector<Vec3r> points;
// Iterate over vertices, storing projections in points
for (vector<WOEdge *>::const_iterator woe = fedges.begin(), woend = fedges.end(); woe != woend;
woe++) {
points.push_back((*woe)->GetaVertex()->GetVertex());
}
return points;
}
void getDefaultViewProscenium(real viewProscenium[4]);
inline void expandProscenium(real proscenium[4], const Polygon3r &polygon)
{
Vec3r bbMin, bbMax;
polygon.getBBox(bbMin, bbMax);
const real epsilon = 1.0e-6;
if (bbMin[0] <= proscenium[0]) {
proscenium[0] = bbMin[0] - epsilon;
}
if (bbMin[1] <= proscenium[2]) {
proscenium[2] = bbMin[1] - epsilon;
}
if (bbMax[0] >= proscenium[1]) {
proscenium[1] = bbMax[0] + epsilon;
}
if (bbMax[1] >= proscenium[3]) {
proscenium[3] = bbMax[1] + epsilon;
}
}
inline void expandProscenium(real proscenium[4], const Vec3r &point)
{
const real epsilon = 1.0e-6;
if (point[0] <= proscenium[0]) {
proscenium[0] = point[0] - epsilon;
}
if (point[1] <= proscenium[2]) {
proscenium[2] = point[1] - epsilon;
}
if (point[0] >= proscenium[1]) {
proscenium[1] = point[0] + epsilon;
}
if (point[1] >= proscenium[3]) {
proscenium[3] = point[1] + epsilon;
}
}
}; // namespace GridHelpers
} /* namespace Freestyle */