Blender V4.3
doublearea.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2013 Alec Jacobson
2 *
3 * SPDX-License-Identifier: MPL-2.0 */
4
9#include "doublearea.h"
10#include "edge_lengths.h"
11
12#include <cassert>
13
14#include <BLI_task.hh>
15
16namespace slim {
17
18/* Sort the elements of a matrix X along a given dimension like matlabs sort
19 * function, assuming X.cols() == 3.
20 *
21 * Templates:
22 * DerivedX derived scalar type, e.g. MatrixXi or MatrixXd
23 * DerivedIX derived integer type, e.g. MatrixXi
24 * Inputs:
25 * X m by n matrix whose entries are to be sorted
26 * dim dimensional along which to sort:
27 * 1 sort each column (matlab default)
28 * 2 sort each row
29 * ascending sort ascending (true, matlab default) or descending (false)
30 * Outputs:
31 * Y m by n matrix whose entries are sorted
32 * IX m by n matrix of indices so that if dim = 1, then in matlab notation
33 * for j = 1:n, Y(:,j) = X(I(:,j),j); end
34 */
35template<typename DerivedX, typename DerivedY, typename DerivedIX>
36static inline void doublearea_sort3(const Eigen::PlainObjectBase<DerivedX> &X,
37 const int dim,
38 const bool ascending,
39 Eigen::PlainObjectBase<DerivedY> &Y,
40 Eigen::PlainObjectBase<DerivedIX> &IX)
41{
42 using namespace Eigen;
43 using namespace std;
44 typedef typename Eigen::PlainObjectBase<DerivedY>::Scalar YScalar;
45 Y = X.template cast<YScalar>();
46 /* Get number of columns (or rows). */
47 int num_outer = (dim == 1 ? X.cols() : X.rows());
48 /* Get number of rows (or columns). */
49 int num_inner = (dim == 1 ? X.rows() : X.cols());
50 assert(num_inner == 3);
51 (void)num_inner;
52 typedef typename Eigen::PlainObjectBase<DerivedIX>::Scalar Index;
53 IX.resize(X.rows(), X.cols());
54 if (dim == 1) {
55 IX.row(0).setConstant(0); /* = Eigen::PlainObjectBase<DerivedIX>::Zero(1,IX.cols());. */
56 IX.row(1).setConstant(1); /* = Eigen::PlainObjectBase<DerivedIX>::Ones (1,IX.cols());. */
57 IX.row(2).setConstant(2); /* = Eigen::PlainObjectBase<DerivedIX>::Ones (1,IX.cols());. */
58 }
59 else {
60 IX.col(0).setConstant(0); /* = Eigen::PlainObjectBase<DerivedIX>::Zero(IX.rows(),1);. */
61 IX.col(1).setConstant(1); /* = Eigen::PlainObjectBase<DerivedIX>::Ones (IX.rows(),1);. */
62 IX.col(2).setConstant(2); /* = Eigen::PlainObjectBase<DerivedIX>::Ones (IX.rows(),1);. */
63 }
64
65 using namespace blender;
66 threading::parallel_for(
67 IndexRange(num_outer), 16000, [&IX, &Y, &dim, &ascending](const IndexRange range) {
68 for (const Index i : range) {
69 YScalar &a = (dim == 1 ? Y(0, i) : Y(i, 0));
70 YScalar &b = (dim == 1 ? Y(1, i) : Y(i, 1));
71 YScalar &c = (dim == 1 ? Y(2, i) : Y(i, 2));
72 Index &ai = (dim == 1 ? IX(0, i) : IX(i, 0));
73 Index &bi = (dim == 1 ? IX(1, i) : IX(i, 1));
74 Index &ci = (dim == 1 ? IX(2, i) : IX(i, 2));
75 if (ascending) {
76 /* 123 132 213 231 312 321. */
77 if (a > b) {
78 std::swap(a, b);
79 std::swap(ai, bi);
80 }
81 /* 123 132 123 231 132 231. */
82 if (b > c) {
83 std::swap(b, c);
84 std::swap(bi, ci);
85 /* 123 123 123 213 123 213. */
86 if (a > b) {
87 std::swap(a, b);
88 std::swap(ai, bi);
89 }
90 /* 123 123 123 123 123 123. */
91 }
92 }
93 else {
94 /* 123 132 213 231 312 321. */
95 if (a < b) {
96 std::swap(a, b);
97 std::swap(ai, bi);
98 }
99 /* 213 312 213 321 312 321. */
100 if (b < c) {
101 std::swap(b, c);
102 std::swap(bi, ci);
103 /* 231 321 231 321 321 321. */
104 if (a < b) {
105 std::swap(a, b);
106 std::swap(ai, bi);
107 }
108 /* 321 321 321 321 321 321. */
109 }
110 }
111 }
112 });
113}
114
115template<typename DerivedV, typename DerivedF, typename DeriveddblA>
116inline void doublearea(const Eigen::PlainObjectBase<DerivedV> &V,
117 const Eigen::PlainObjectBase<DerivedF> &F,
118 Eigen::PlainObjectBase<DeriveddblA> &dblA)
119{
120 const int dim = V.cols();
121 /* Only support triangles. */
122 assert(F.cols() == 3);
123 const size_t m = F.rows();
124 /* Compute edge lengths. */
125 Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 3> l;
126
127 /* Projected area helper. */
128 const auto &proj_doublearea = [&V, &F](const int x, const int y, const int f) -> double {
129 auto rx = V(F(f, 0), x) - V(F(f, 2), x);
130 auto sx = V(F(f, 1), x) - V(F(f, 2), x);
131 auto ry = V(F(f, 0), y) - V(F(f, 2), y);
132 auto sy = V(F(f, 1), y) - V(F(f, 2), y);
133 return rx * sy - ry * sx;
134 };
135
136 switch (dim) {
137 case 3: {
138 dblA = Eigen::PlainObjectBase<DeriveddblA>::Zero(m, 1);
139 for (size_t f = 0; f < m; f++) {
140 for (int d = 0; d < 3; d++) {
141 double dblAd = proj_doublearea(d, (d + 1) % 3, f);
142 dblA(f) += dblAd * dblAd;
143 }
144 }
145 dblA = dblA.array().sqrt().eval();
146 break;
147 }
148 case 2: {
149 dblA.resize(m, 1);
150 for (size_t f = 0; f < m; f++) {
151 dblA(f) = proj_doublearea(0, 1, f);
152 }
153 break;
154 }
155 default: {
156 edge_lengths(V, F, l);
157 return doublearea(l, dblA);
158 }
159 }
160}
161
162template<typename Derivedl, typename DeriveddblA>
163inline void doublearea(const Eigen::PlainObjectBase<Derivedl> &ul,
164 Eigen::PlainObjectBase<DeriveddblA> &dblA)
165{
166 using namespace Eigen;
167 using namespace std;
168 typedef typename Derivedl::Index Index;
169 /* Only support triangles. */
170 assert(ul.cols() == 3);
171 /* Number of triangles. */
172 const Index m = ul.rows();
173 Eigen::Matrix<typename Derivedl::Scalar, Eigen::Dynamic, 3> l;
174 MatrixXi _;
175 /* "Lecture Notes on Geometric Robustness" Shewchuck 09, Section 3.1
176 * http://www.cs.berkeley.edu/~jrs/meshpapers/robnotes.pdf
177 *
178 * "Miscalculating Area and Angles of a Needle-like Triangle"
179 * https://people.eecs.berkeley.edu/~wkahan/Triangle.pdf
180 */
181 doublearea_sort3(ul, 2, false, l, _);
182 dblA.resize(l.rows(), 1);
183
184 using namespace blender;
185 threading::parallel_for(IndexRange(m), 1000, [&l, &dblA](const IndexRange range) {
186 for (const Index i : range) {
187 /* Kahan's Heron's formula. */
188 const typename Derivedl::Scalar arg = (l(i, 0) + (l(i, 1) + l(i, 2))) *
189 (l(i, 2) - (l(i, 0) - l(i, 1))) *
190 (l(i, 2) + (l(i, 0) - l(i, 1))) *
191 (l(i, 0) + (l(i, 1) - l(i, 2)));
192 dblA(i) = 2.0 * 0.25 * sqrt(arg);
193 assert(l(i, 2) - (l(i, 0) - l(i, 1)) && "FAILED KAHAN'S ASSERTION");
194 assert(dblA(i) == dblA(i) && "DOUBLEAREA() PRODUCED NaN");
195 }
196 });
197}
198
199} // namespace slim
sqrt(x)+1/max(0
#define X
#define Y
ATTR_WARN_UNUSED_RESULT const BMLoop * l
local_group_size(16, 16) .push_constant(Type b
IndexRange range
ccl_device_inline int4 cast(const float4 a)
Definition math_float4.h:29
#define F
void edge_lengths(const Eigen::PlainObjectBase< DerivedV > &V, const Eigen::PlainObjectBase< DerivedF > &F, Eigen::PlainObjectBase< DerivedL > &L)
void doublearea(const Eigen::PlainObjectBase< DerivedV > &V, const Eigen::PlainObjectBase< DerivedF > &F, Eigen::PlainObjectBase< DeriveddblA > &dblA)
static void doublearea_sort3(const Eigen::PlainObjectBase< DerivedX > &X, const int dim, const bool ascending, Eigen::PlainObjectBase< DerivedY > &Y, Eigen::PlainObjectBase< DerivedIX > &IX)
CCL_NAMESPACE_BEGIN struct Window V