Skip to content

Commit 21504d4

Browse files
authored
Merge pull request #1850 from llnl/feature/whitlock/klee_shaping_transform
Klee scaling enhancements
2 parents cf8de58 + a241d00 commit 21504d4

22 files changed

Lines changed: 539 additions & 211 deletions

RELEASE-NOTES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ The Axom project release numbers follow [Semantic Versioning](http://semver.org/
2626
- Primal: Adds `NURBSPatch::isTriviallyTrimmed()` to check if the trimming curves for a patch lie on the patch boundaries
2727
- Quest: Adds support for reading mfem files with variable order NURBS curves (requires mfem>4.9).
2828
- Quest: Adds OMP support for fast GWN methods for STL/Triangulated STEP input and linearized NURBS Curve input.
29+
- Klee: Adds an optional "center" parameter in scale operators that permits scaling relative to a custom center point.
2930

3031
### Removed
3132

src/axom/core/numerics/transforms.hpp

Lines changed: 79 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "axom/config.hpp"
1010
#include "axom/core/numerics/Matrix.hpp"
11+
#include "axom/core/ArrayView.hpp"
1112

1213
#include <cassert>
1314
#include <cmath>
@@ -133,6 +134,33 @@ Matrix<T> axisRotation(double angleRad, double x, double y, double z)
133134
return M;
134135
}
135136

137+
/*!
138+
* \brief Return translation matrix.
139+
*
140+
* \param tx The translation in x.
141+
* \param ty The translation in y.
142+
*
143+
* \return A Matrix containing the translation transform.
144+
*/
145+
template <typename T = double>
146+
Matrix<T> translate(T tx, T ty)
147+
{
148+
Matrix<T> M = Matrix<T>::identity(3);
149+
M(0, 2) = tx;
150+
M(1, 2) = ty;
151+
return M;
152+
}
153+
154+
template <typename T = double>
155+
Matrix<T> translate(T tx, T ty, T tz)
156+
{
157+
Matrix<T> M = Matrix<T>::identity(4);
158+
M(0, 3) = tx;
159+
M(1, 3) = ty;
160+
M(2, 3) = tz;
161+
return M;
162+
}
163+
136164
/*!
137165
* \brief Return scaling matrix.
138166
*
@@ -194,30 +222,66 @@ Matrix<T> scale(T sx, T sy, int ndims = 3)
194222
}
195223

196224
/*!
197-
* \brief Return translation matrix.
225+
* \brief Return scaling matrix relative to a center point.
198226
*
199-
* \param tx The translation in x.
200-
* \param ty The translation in y.
227+
* \param sx The scaling value in x.
228+
* \param sy The scaling value in y.
229+
* \param center The center point.
201230
*
202-
* \return A Matrix containing the translation transform.
231+
* \return A 3x3 Matrix containing the scaling transform.
203232
*/
204233
template <typename T = double>
205-
Matrix<T> translate(T tx, T ty)
234+
Matrix<T> scale(T sx, T sy, const axom::ArrayView<T> &center)
206235
{
207-
Matrix<T> M = Matrix<T>::identity(3);
208-
M(0, 2) = tx;
209-
M(1, 2) = ty;
210-
return M;
236+
assert(center.size() == 2);
237+
const T zero {0};
238+
if(axom::utilities::isNearlyEqual(center[0], zero) &&
239+
axom::utilities::isNearlyEqual(center[1], zero))
240+
{
241+
return scale(sx, sy);
242+
}
243+
244+
const auto T0 = translate(-center[0], -center[1]);
245+
const auto S = scale(sx, sy, 3);
246+
const auto T1 = translate(center[0], center[1]);
247+
248+
Matrix<T> TS(Matrix<T>::identity(3)), result(Matrix<T>::identity(3));
249+
matrix_multiply(T1, S, TS);
250+
matrix_multiply(TS, T0, result);
251+
252+
return result;
211253
}
212254

255+
/*!
256+
* \brief Return scaling matrix relative to a center point.
257+
*
258+
* \param sx The scaling value in x.
259+
* \param sy The scaling value in y.
260+
* \param center The center point.
261+
*
262+
* \return A 4x4 Matrix containing the scaling transform.
263+
*/
213264
template <typename T = double>
214-
Matrix<T> translate(T tx, T ty, T tz)
265+
Matrix<T> scale(T sx, T sy, T sz, const axom::ArrayView<T> &center)
215266
{
216-
Matrix<T> M = Matrix<T>::identity(4);
217-
M(0, 3) = tx;
218-
M(1, 3) = ty;
219-
M(2, 3) = tz;
220-
return M;
267+
assert(center.size() == 3);
268+
const T zero {0};
269+
if(axom::utilities::isNearlyEqual(center[0], zero) &&
270+
axom::utilities::isNearlyEqual(center[1], zero) &&
271+
axom::utilities::isNearlyEqual(center[2], zero))
272+
{
273+
return scale(sx, sy, sz, 4);
274+
}
275+
276+
const auto T0 = translate(-center[0], -center[1], -center[2]);
277+
const auto S = scale(sx, sy, sz, 4);
278+
const auto T1 = translate(center[0], center[1], center[2]);
279+
280+
Matrix<T> TS(Matrix<T>::identity(4)), result(Matrix<T>::identity(4));
281+
matrix_multiply(T1, S, TS);
282+
matrix_multiply(TS, T0, result);
283+
284+
return result;
221285
}
222286

223287
} // end namespace transforms

src/axom/core/tests/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ set(core_serial_tests
4646
numerics_lu.hpp
4747
numerics_matrix.hpp
4848
numerics_matvecops.hpp
49+
numerics_transforms.hpp
4950
numerics_polynomial_solvers.hpp
5051

5152
utils_endianness.hpp
@@ -226,4 +227,3 @@ if (ENABLE_BENCHMARKS)
226227
COMMAND ${test_name} --benchmark_min_time=0.0001s)
227228
endforeach()
228229
endif()
229-

src/axom/core/tests/core_serial_main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "numerics_lu.hpp"
4141
#include "numerics_matrix.hpp"
4242
#include "numerics_matvecops.hpp"
43+
#include "numerics_transforms.hpp"
4344
#include "numerics_polynomial_solvers.hpp"
4445
#include "numerics_quadrature.hpp"
4546

src/axom/core/tests/core_static_array.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ struct DevicePair
2525

2626
AXOM_HOST_DEVICE explicit DevicePair(int value) : first(value), second(-value) { }
2727

28+
AXOM_HOST_DEVICE DevicePair(const DevicePair& obj) : first(obj.first), second(obj.second) { }
29+
2830
AXOM_HOST_DEVICE DevicePair& operator=(const DevicePair& other)
2931
{
3032
first = other.first;
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Copyright (c) Lawrence Livermore National Security, LLC and other
2+
// Axom Project Contributors. See top-level LICENSE and COPYRIGHT
3+
// files for dates and other details.
4+
//
5+
// SPDX-License-Identifier: (BSD-3-Clause)
6+
7+
#include "gtest/gtest.h"
8+
9+
#include "axom/core/ArrayView.hpp"
10+
#include "axom/core/numerics/matvecops.hpp"
11+
#include "axom/core/numerics/transforms.hpp"
12+
13+
namespace
14+
{
15+
void expect_matrix_near(const axom::numerics::Matrix<double>& actual,
16+
const axom::numerics::Matrix<double>& expected,
17+
double tolerance = 1e-12)
18+
{
19+
ASSERT_EQ(actual.getNumRows(), expected.getNumRows());
20+
ASSERT_EQ(actual.getNumColumns(), expected.getNumColumns());
21+
22+
for(axom::IndexType i = 0; i < actual.getNumRows(); ++i)
23+
{
24+
for(axom::IndexType j = 0; j < actual.getNumColumns(); ++j)
25+
{
26+
EXPECT_NEAR(actual(i, j), expected(i, j), tolerance);
27+
}
28+
}
29+
}
30+
31+
void expect_vector_near(const double* actual, const double* expected, int size, double tolerance = 1e-12)
32+
{
33+
for(int i = 0; i < size; ++i)
34+
{
35+
EXPECT_NEAR(actual[i], expected[i], tolerance);
36+
}
37+
}
38+
} // namespace
39+
40+
TEST(numerics_transforms, scale_2d_about_center)
41+
{
42+
double centerData[2] = {2.0, 3.0};
43+
axom::ArrayView<double> center(centerData, 2);
44+
45+
auto actual = axom::numerics::transforms::scale(4.0, 5.0, center);
46+
47+
axom::numerics::Matrix<double> expected = axom::numerics::Matrix<double>::identity(3);
48+
expected(0, 0) = 4.0;
49+
expected(1, 1) = 5.0;
50+
expected(0, 2) = -6.0;
51+
expected(1, 2) = -12.0;
52+
expect_matrix_near(actual, expected);
53+
54+
double point[3] = {3.0, 4.0, 1.0};
55+
double result[3] = {0.0, 0.0, 0.0};
56+
double expectedPoint[3] = {6.0, 8.0, 1.0};
57+
axom::numerics::matrix_vector_multiply(actual, point, result);
58+
expect_vector_near(result, expectedPoint, 3);
59+
}
60+
61+
TEST(numerics_transforms, scale_3d_about_center)
62+
{
63+
double centerData[3] = {0.5, 0.5, 0.5};
64+
axom::ArrayView<double> center(centerData, 3);
65+
66+
auto actual = axom::numerics::transforms::scale(2.0, 3.0, 4.0, center);
67+
68+
axom::numerics::Matrix<double> expected = axom::numerics::Matrix<double>::identity(4);
69+
expected(0, 0) = 2.0;
70+
expected(1, 1) = 3.0;
71+
expected(2, 2) = 4.0;
72+
expected(0, 3) = -0.5;
73+
expected(1, 3) = -1.0;
74+
expected(2, 3) = -1.5;
75+
expect_matrix_near(actual, expected);
76+
77+
double point[4] = {1.5, 1.5, 1.5, 1.0};
78+
double result[4] = {0.0, 0.0, 0.0, 0.0};
79+
double expectedPoint[4] = {2.5, 3.5, 4.5, 1.0};
80+
axom::numerics::matrix_vector_multiply(actual, point, result);
81+
expect_vector_near(result, expectedPoint, 4);
82+
}
83+
84+
TEST(numerics_transforms, scale_about_zero_center_matches_origin_scale)
85+
{
86+
double center2dData[2] = {0.0, 0.0};
87+
axom::ArrayView<double> center2d(center2dData, 2);
88+
expect_matrix_near(axom::numerics::transforms::scale(2.0, 3.0, center2d),
89+
axom::numerics::transforms::scale(2.0, 3.0));
90+
91+
double center3dData[3] = {0.0, 0.0, 0.0};
92+
axom::ArrayView<double> center3d(center3dData, 3);
93+
expect_matrix_near(axom::numerics::transforms::scale(2.0, 3.0, 4.0, center3d),
94+
axom::numerics::transforms::scale(2.0, 3.0, 4.0, 4));
95+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright (c) Lawrence Livermore National Security, LLC and other
2+
// Axom Project Contributors. See top-level LICENSE and COPYRIGHT
3+
// files for dates and other details.
4+
//
5+
// SPDX-License-Identifier: (BSD-3-Clause)
6+
#include "axom/klee/AffineMatrixVisitor.hpp"
7+
8+
namespace axom::klee
9+
{
10+
11+
AffineMatrixVisitor::AffineMatrixVisitor()
12+
: GeometryOperatorVisitor()
13+
, m_isValid(false)
14+
, m_matrix(4, 4)
15+
{ }
16+
17+
void AffineMatrixVisitor::visit(const klee::Translation& translation)
18+
{
19+
m_matrix = translation.toMatrix();
20+
m_isValid = true;
21+
}
22+
void AffineMatrixVisitor::visit(const klee::Rotation& rotation)
23+
{
24+
m_matrix = rotation.toMatrix();
25+
m_isValid = true;
26+
}
27+
void AffineMatrixVisitor::visit(const klee::Scale& scale)
28+
{
29+
m_matrix = scale.toMatrix();
30+
m_isValid = true;
31+
}
32+
void AffineMatrixVisitor::visit(const klee::UnitConverter& converter)
33+
{
34+
m_matrix = converter.toMatrix();
35+
m_isValid = true;
36+
}
37+
38+
void AffineMatrixVisitor::visit(const klee::CompositeOperator&)
39+
{
40+
SLIC_WARNING_ROOT("CompositeOperator not supported for Shaper query");
41+
m_isValid = false;
42+
}
43+
void AffineMatrixVisitor::visit(const klee::SliceOperator&)
44+
{
45+
SLIC_WARNING_ROOT("SliceOperator not yet supported for Shaper query");
46+
m_isValid = false;
47+
}
48+
49+
} // end namespace axom::klee
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright (c) Lawrence Livermore National Security, LLC and other
2+
// Axom Project Contributors. See top-level LICENSE and COPYRIGHT
3+
// files for dates and other details.
4+
//
5+
// SPDX-License-Identifier: (BSD-3-Clause)
6+
#ifndef AXOM_KLEE_AFFINE_MATRIX_VISITOR_HPP_
7+
#define AXOM_KLEE_AFFINE_MATRIX_VISITOR_HPP_
8+
#include "axom/klee/GeometryOperators.hpp"
9+
10+
namespace axom::klee
11+
{
12+
13+
/*!
14+
* \brief Implementation of a GeometryOperatorVisitor for processing klee shape operators
15+
*
16+
* This class extracts the matrix form of supported operators and marks the operator as unvalid otherwise
17+
* To use, check the \a isValid() function after visiting and then call the \a getMatrix() function.
18+
*/
19+
class AffineMatrixVisitor : public GeometryOperatorVisitor
20+
{
21+
public:
22+
AffineMatrixVisitor();
23+
24+
void visit(const klee::Translation& translation) override;
25+
void visit(const klee::Rotation& rotation) override;
26+
void visit(const klee::Scale& scale) override;
27+
void visit(const klee::UnitConverter& converter) override;
28+
29+
void visit(const klee::CompositeOperator&) override;
30+
void visit(const klee::SliceOperator&) override;
31+
32+
const numerics::Matrix<double>& getMatrix() const { return m_matrix; }
33+
bool isValid() const { return m_isValid; }
34+
35+
private:
36+
bool m_isValid;
37+
numerics::Matrix<double> m_matrix;
38+
};
39+
40+
} // end namespace axom::klee
41+
42+
#endif

src/axom/klee/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ axom_component_requires(NAME Klee
1010
# Specify all headers/sources
1111
#------------------------------------------------------------------------------
1212
set(klee_headers
13+
AffineMatrixVisitor.hpp
1314
Dimensions.hpp
1415
Geometry.hpp
1516
GeometryOperators.hpp
@@ -26,6 +27,7 @@ set(klee_internal_headers
2627
)
2728

2829
set(klee_sources
30+
AffineMatrixVisitor.cpp
2931
Geometry.cpp
3032
GeometryOperators.cpp
3133
KleeError.cpp

0 commit comments

Comments
 (0)