1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
.project
|
.project
|
||||||
|
CMakeLists.txt.user
|
||||||
|
|||||||
@@ -88,6 +88,12 @@ add_subdirectory (src/OpenMesh/Core)
|
|||||||
add_subdirectory (src/OpenMesh/Tools)
|
add_subdirectory (src/OpenMesh/Tools)
|
||||||
add_subdirectory (src/OpenMesh/Apps)
|
add_subdirectory (src/OpenMesh/Apps)
|
||||||
|
|
||||||
|
set(OPENMESH_BENCHMARK_DIR CACHE PATH "Source path of benchmark (https://github.com/google/benchmark).")
|
||||||
|
if (OPENMESH_BENCHMARK_DIR)
|
||||||
|
add_subdirectory(${OPENMESH_BENCHMARK_DIR} benchmark)
|
||||||
|
add_subdirectory(src/Benchmark)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Do not build unit tests when build as external library
|
# Do not build unit tests when build as external library
|
||||||
if(${PROJECT_NAME} MATCHES "OpenMesh")
|
if(${PROJECT_NAME} MATCHES "OpenMesh")
|
||||||
add_subdirectory (src/Unittests)
|
add_subdirectory (src/Unittests)
|
||||||
|
|||||||
12
src/Benchmark/CMakeLists.txt
Normal file
12
src/Benchmark/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
set (SOURCES "")
|
||||||
|
list (APPEND SOURCES
|
||||||
|
main.cpp
|
||||||
|
VectorT_new.cpp
|
||||||
|
VectorT_legacy.cpp
|
||||||
|
VectorT_dummy_data.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(OMBenchmark ${SOURCES})
|
||||||
|
set_target_properties(OMBenchmark PROPERTIES
|
||||||
|
INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/..")
|
||||||
|
target_link_libraries(OMBenchmark benchmark OpenMeshCore)
|
||||||
163
src/Benchmark/VectorT.cpp
Normal file
163
src/Benchmark/VectorT.cpp
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* VectorT.cpp
|
||||||
|
*
|
||||||
|
* Created on: Nov 19, 2015
|
||||||
|
* Author: ebke
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BMPOSTFIX
|
||||||
|
#error "Do not compile directly."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#define ASSEMBLE_(POSTFIX, PREFIX) PREFIX ## POSTFIX
|
||||||
|
#define ASSEMBLE(POSTFIX, PREFIX) ASSEMBLE_(POSTFIX, PREFIX)
|
||||||
|
#define MYBENCHMARK(NAME) BENCHMARK(NAME)
|
||||||
|
#define MYBENCHMARK_TEMPLATE(NAME, TYPE) BENCHMARK_TEMPLATE(NAME, TYPE)
|
||||||
|
|
||||||
|
template<class Vec>
|
||||||
|
static inline
|
||||||
|
typename std::enable_if<Vec::size_ == 3, Vec>::type
|
||||||
|
testVec() {
|
||||||
|
return Vec(1.1, 1.2, 1.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Vec>
|
||||||
|
static inline
|
||||||
|
typename std::enable_if<Vec::size_ == 4, Vec>::type
|
||||||
|
testVec() {
|
||||||
|
return Vec(1.1, 1.2, 1.3, 1.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Vec>
|
||||||
|
static void ASSEMBLE(BMPOSTFIX, Vec_add_compare)(benchmark::State& state) {
|
||||||
|
Vec v1(0.0);
|
||||||
|
Vec v2(1000.0);
|
||||||
|
while (state.KeepRunning()) {
|
||||||
|
v1 += testVec<Vec>();
|
||||||
|
v2 -= testVec<Vec>();
|
||||||
|
if (v1 == v2) {
|
||||||
|
v1 -= v2;
|
||||||
|
v2 += v1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Just so nothing gets optimized away.
|
||||||
|
static double dummy;
|
||||||
|
dummy = v1.norm() + v2.norm();
|
||||||
|
static_cast<void>(dummy);
|
||||||
|
}
|
||||||
|
|
||||||
|
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_compare), OpenMesh::Vec3d);
|
||||||
|
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_compare), OpenMesh::Vec3f);
|
||||||
|
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_compare), OpenMesh::Vec4d);
|
||||||
|
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_compare), OpenMesh::Vec4f);
|
||||||
|
|
||||||
|
template<class Vec>
|
||||||
|
static void ASSEMBLE(BMPOSTFIX, Vec_cross_product)(benchmark::State& state) {
|
||||||
|
Vec v1(0.0);
|
||||||
|
Vec v2(1000.0);
|
||||||
|
while (state.KeepRunning()) {
|
||||||
|
v1 += testVec<Vec>();
|
||||||
|
v2 -= testVec<Vec>();
|
||||||
|
v1 = (v1 % v2);
|
||||||
|
}
|
||||||
|
// Just so nothing gets optimized away.
|
||||||
|
static double dummy;
|
||||||
|
dummy = v1.norm() + v2.norm();
|
||||||
|
static_cast<void>(dummy);
|
||||||
|
}
|
||||||
|
|
||||||
|
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_cross_product), OpenMesh::Vec3d);
|
||||||
|
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_cross_product), OpenMesh::Vec3f);
|
||||||
|
|
||||||
|
template<class Vec>
|
||||||
|
static void ASSEMBLE(BMPOSTFIX, Vec_scalar_product)(benchmark::State& state) {
|
||||||
|
Vec v1(0.0);
|
||||||
|
Vec v2(1000.0);
|
||||||
|
double acc = 0;
|
||||||
|
while (state.KeepRunning()) {
|
||||||
|
v1 += testVec<Vec>();
|
||||||
|
v2 -= testVec<Vec>();
|
||||||
|
acc += (v1 | v2);
|
||||||
|
}
|
||||||
|
// Otherwise GCC will optimize everything away.
|
||||||
|
static double dummy;
|
||||||
|
dummy = acc;
|
||||||
|
static_cast<void>(dummy);
|
||||||
|
}
|
||||||
|
|
||||||
|
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_scalar_product), OpenMesh::Vec3d);
|
||||||
|
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_scalar_product), OpenMesh::Vec3f);
|
||||||
|
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_scalar_product), OpenMesh::Vec4d);
|
||||||
|
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_scalar_product), OpenMesh::Vec4f);
|
||||||
|
|
||||||
|
template<class Vec>
|
||||||
|
static void ASSEMBLE(BMPOSTFIX, Vec_norm)(benchmark::State& state) {
|
||||||
|
Vec v1(0.0);
|
||||||
|
double acc = 0;
|
||||||
|
while (state.KeepRunning()) {
|
||||||
|
v1 += testVec<Vec>();
|
||||||
|
acc += v1.norm();
|
||||||
|
}
|
||||||
|
// Otherwise GCC will optimize everything away.
|
||||||
|
static double dummy;
|
||||||
|
dummy = acc;
|
||||||
|
static_cast<void>(dummy);
|
||||||
|
}
|
||||||
|
|
||||||
|
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_norm), OpenMesh::Vec3d);
|
||||||
|
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_norm), OpenMesh::Vec3f);
|
||||||
|
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_norm), OpenMesh::Vec4d);
|
||||||
|
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_norm), OpenMesh::Vec4f);
|
||||||
|
|
||||||
|
template<class Vec>
|
||||||
|
static void ASSEMBLE(BMPOSTFIX, Vec_times_scalar)(benchmark::State& state) {
|
||||||
|
Vec v1(0.0);
|
||||||
|
while (state.KeepRunning()) {
|
||||||
|
v1 += testVec<Vec>();
|
||||||
|
v1 *= static_cast<decltype(v1.norm())>(1.0)/v1[0];
|
||||||
|
v1 *= v1[1];
|
||||||
|
}
|
||||||
|
// Otherwise GCC will optimize everything away.
|
||||||
|
static double dummy;
|
||||||
|
dummy = v1.norm();
|
||||||
|
static_cast<void>(dummy);
|
||||||
|
}
|
||||||
|
|
||||||
|
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_times_scalar), OpenMesh::Vec3d);
|
||||||
|
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_times_scalar), OpenMesh::Vec3f);
|
||||||
|
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_times_scalar), OpenMesh::Vec4d);
|
||||||
|
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_times_scalar), OpenMesh::Vec4f);
|
||||||
|
|
||||||
|
#include "VectorT_dummy_data.hpp"
|
||||||
|
|
||||||
|
template<class Vec>
|
||||||
|
static void ASSEMBLE(BMPOSTFIX, Vec_add_in_place)(benchmark::State& state) {
|
||||||
|
auto v = make_dummy_vector<Vec>();
|
||||||
|
while (state.KeepRunning()) {
|
||||||
|
v += v;
|
||||||
|
}
|
||||||
|
// Otherwise GCC will optimize everything away.
|
||||||
|
static double dummy = observe_dummy_vector(v);
|
||||||
|
static_cast<void>(dummy);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Vec>
|
||||||
|
static void ASSEMBLE(BMPOSTFIX, Vec_add_temporary)(benchmark::State& state) {
|
||||||
|
auto v = make_dummy_vector<Vec>();
|
||||||
|
while (state.KeepRunning()) {
|
||||||
|
v = v + v;
|
||||||
|
}
|
||||||
|
// Otherwise GCC will optimize everything away.
|
||||||
|
static double dummy = observe_dummy_vector(v);
|
||||||
|
static_cast<void>(dummy);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef OpenMesh::VectorT<std::valarray<double>, 3> Vec3VAd;
|
||||||
|
typedef OpenMesh::VectorT<std::complex<double>, 3> Vec3Cd;
|
||||||
|
|
||||||
|
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_in_place), Vec3VAd);
|
||||||
|
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_temporary), Vec3VAd);
|
||||||
|
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_in_place), Vec3Cd);
|
||||||
|
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_temporary), Vec3Cd);
|
||||||
5
src/Benchmark/VectorT_dummy_data.cpp
Normal file
5
src/Benchmark/VectorT_dummy_data.cpp
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#include "VectorT_dummy_data.hpp"
|
||||||
|
|
||||||
|
template<> std::valarray<double> make_dummy_component() {
|
||||||
|
return std::valarray<double>(128);
|
||||||
|
}
|
||||||
40
src/Benchmark/VectorT_dummy_data.hpp
Normal file
40
src/Benchmark/VectorT_dummy_data.hpp
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <valarray>
|
||||||
|
#include <complex>
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T make_dummy_component() {
|
||||||
|
return T();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> std::valarray<double> make_dummy_component();
|
||||||
|
|
||||||
|
template<typename Vec>
|
||||||
|
Vec make_dummy_vector() {
|
||||||
|
return Vec(make_dummy_component<typename Vec::value_type>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Scalar>
|
||||||
|
double observe_dummy_component(const Scalar& _s) {
|
||||||
|
return _s;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
double observe_dummy_component(const std::valarray<T>& _s) {
|
||||||
|
return _s.sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
double observe_dummy_component(const std::complex<T>& _s) {
|
||||||
|
return _s.real() + _s.imag();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Vec>
|
||||||
|
double observe_dummy_vector(const Vec& _vec) {
|
||||||
|
double result = 0.0;
|
||||||
|
for (int dim = 0; dim < _vec.dim(); ++dim) {
|
||||||
|
result += observe_dummy_component(_vec[dim]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
14
src/Benchmark/VectorT_legacy.cpp
Normal file
14
src/Benchmark/VectorT_legacy.cpp
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* VectorT_legacy.cpp
|
||||||
|
*
|
||||||
|
* Created on: Nov 19, 2015
|
||||||
|
* Author: ebke
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <benchmark/benchmark_api.h>
|
||||||
|
|
||||||
|
#define OPENMESH_VECTOR_LEGACY
|
||||||
|
#include <OpenMesh/Core/Geometry/VectorT.hh>
|
||||||
|
|
||||||
|
#define BMPOSTFIX _Legacy
|
||||||
|
#include "VectorT.cpp"
|
||||||
12
src/Benchmark/VectorT_new.cpp
Normal file
12
src/Benchmark/VectorT_new.cpp
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
* VectorT_new.cpp
|
||||||
|
*
|
||||||
|
* Created on: Nov 19, 2015
|
||||||
|
* Author: ebke
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <benchmark/benchmark_api.h>
|
||||||
|
#include <OpenMesh/Core/Geometry/VectorT.hh>
|
||||||
|
|
||||||
|
#define BMPOSTFIX _CPP11
|
||||||
|
#include "VectorT.cpp"
|
||||||
10
src/Benchmark/main.cpp
Normal file
10
src/Benchmark/main.cpp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* main.cpp
|
||||||
|
*
|
||||||
|
* Created on: Nov 19, 2015
|
||||||
|
* Author: ebke
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <benchmark/benchmark_api.h>
|
||||||
|
|
||||||
|
BENCHMARK_MAIN();
|
||||||
832
src/OpenMesh/Core/Geometry/Vector11T.hh
Normal file
832
src/OpenMesh/Core/Geometry/Vector11T.hh
Normal file
@@ -0,0 +1,832 @@
|
|||||||
|
/* ========================================================================= *
|
||||||
|
* *
|
||||||
|
* OpenMesh *
|
||||||
|
* Copyright (c) 2001-2015, RWTH-Aachen University *
|
||||||
|
* Department of Computer Graphics and Multimedia *
|
||||||
|
* All rights reserved. *
|
||||||
|
* www.openmesh.org *
|
||||||
|
* *
|
||||||
|
*---------------------------------------------------------------------------*
|
||||||
|
* This file is part of OpenMesh. *
|
||||||
|
*---------------------------------------------------------------------------*
|
||||||
|
* *
|
||||||
|
* Redistribution and use in source and binary forms, with or without *
|
||||||
|
* modification, are permitted provided that the following conditions *
|
||||||
|
* are met: *
|
||||||
|
* *
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, *
|
||||||
|
* this list of conditions and the following disclaimer. *
|
||||||
|
* *
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright *
|
||||||
|
* notice, this list of conditions and the following disclaimer in the *
|
||||||
|
* documentation and/or other materials provided with the distribution. *
|
||||||
|
* *
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its *
|
||||||
|
* contributors may be used to endorse or promote products derived from *
|
||||||
|
* this software without specific prior written permission. *
|
||||||
|
* *
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||||
|
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
|
||||||
|
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||||
|
* *
|
||||||
|
* ========================================================================= */
|
||||||
|
|
||||||
|
#ifndef OPENMESH_SRC_OPENMESH_CORE_GEOMETRY_VECTOR11T_HH_
|
||||||
|
#define OPENMESH_SRC_OPENMESH_CORE_GEOMETRY_VECTOR11T_HH_
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <utility>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <numeric>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <cmath>
|
||||||
|
#include <ostream>
|
||||||
|
#include <istream>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
// This header is not needed by this file but expected by others including
|
||||||
|
// this file.
|
||||||
|
#include <OpenMesh/Core/System/config.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helpers for VectorT
|
||||||
|
*/
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
template<typename ... Ts>
|
||||||
|
struct are_convertible_to;
|
||||||
|
|
||||||
|
template<typename To, typename From, typename ... Froms>
|
||||||
|
struct are_convertible_to<To, From, Froms...> {
|
||||||
|
static constexpr bool value = std::is_convertible<From, To>::value
|
||||||
|
&& are_convertible_to<To, Froms...>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename To, typename From>
|
||||||
|
struct are_convertible_to<To, From> : public std::is_convertible<From, To> {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace OpenMesh {
|
||||||
|
|
||||||
|
template<typename Scalar, int DIM>
|
||||||
|
class VectorT {
|
||||||
|
|
||||||
|
static_assert(DIM >= 1, "VectorT requires positive dimensionality.");
|
||||||
|
|
||||||
|
private:
|
||||||
|
using container = std::array<Scalar, DIM>;
|
||||||
|
container values_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//---------------------------------------------------------------- class info
|
||||||
|
|
||||||
|
/// the type of the scalar used in this template
|
||||||
|
typedef Scalar value_type;
|
||||||
|
|
||||||
|
/// type of this vector
|
||||||
|
typedef VectorT<Scalar, DIM> vector_type;
|
||||||
|
|
||||||
|
/// returns dimension of the vector (deprecated)
|
||||||
|
static constexpr int dim() {
|
||||||
|
return DIM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns dimension of the vector
|
||||||
|
static constexpr size_t size() {
|
||||||
|
return DIM;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr const size_t size_ = DIM;
|
||||||
|
|
||||||
|
//-------------------------------------------------------------- constructors
|
||||||
|
|
||||||
|
/// default constructor creates uninitialized values.
|
||||||
|
constexpr VectorT() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a vector with all components set to v.
|
||||||
|
*/
|
||||||
|
explicit VectorT(const Scalar &v) {
|
||||||
|
vectorize(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ... T,
|
||||||
|
typename = typename std::enable_if<sizeof...(T) == DIM>::type,
|
||||||
|
typename = typename std::enable_if<
|
||||||
|
are_convertible_to<Scalar, T...>::value>::type>
|
||||||
|
constexpr VectorT(T... vs) : values_ { {static_cast<Scalar>(vs)...} } {
|
||||||
|
static_assert(sizeof...(T) == DIM,
|
||||||
|
"Invalid number of components specified in constructor.");
|
||||||
|
static_assert(are_convertible_to<Scalar, T...>::value,
|
||||||
|
"Not all components are convertible to Scalar.");
|
||||||
|
}
|
||||||
|
|
||||||
|
VectorT(const VectorT &rhs) = default;
|
||||||
|
VectorT(VectorT &&rhs) = default;
|
||||||
|
VectorT &operator=(const VectorT &rhs) = default;
|
||||||
|
VectorT &operator=(VectorT &&rhs) = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only for 4-component vectors with division operator on their
|
||||||
|
* Scalar: Dehomogenization.
|
||||||
|
*/
|
||||||
|
template<typename S = Scalar, int D = DIM>
|
||||||
|
auto homogenized() const ->
|
||||||
|
typename std::enable_if<D == 4,
|
||||||
|
VectorT<decltype(std::declval<S>()/std::declval<S>()), DIM>>::type {
|
||||||
|
static_assert(D == DIM, "D and DIM need to be identical. (Never "
|
||||||
|
"override the default template arguments.)");
|
||||||
|
static_assert(std::is_same<S, Scalar>::value, "S and Scalar need "
|
||||||
|
"to be the same type. (Never override the default template "
|
||||||
|
"arguments.)");
|
||||||
|
return VectorT(
|
||||||
|
values_[0]/values_[3],
|
||||||
|
values_[1]/values_[3],
|
||||||
|
values_[2]/values_[3],
|
||||||
|
1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// construct from a value array or any other iterator
|
||||||
|
template<typename Iterator,
|
||||||
|
typename = decltype(
|
||||||
|
*std::declval<Iterator&>(), void(),
|
||||||
|
++std::declval<Iterator&>(), void())>
|
||||||
|
explicit VectorT(Iterator it) {
|
||||||
|
std::copy_n(it, DIM, values_.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// copy & cast constructor (explicit)
|
||||||
|
template<typename otherScalarType,
|
||||||
|
typename = typename std::enable_if<
|
||||||
|
std::is_convertible<otherScalarType, Scalar>::value>>
|
||||||
|
explicit VectorT(const VectorT<otherScalarType, DIM>& _rhs) {
|
||||||
|
operator=(_rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------- casts
|
||||||
|
|
||||||
|
/// cast from vector with a different scalar type
|
||||||
|
template<typename OtherScalar,
|
||||||
|
typename = typename std::enable_if<
|
||||||
|
std::is_convertible<OtherScalar, Scalar>::value>>
|
||||||
|
vector_type& operator=(const VectorT<OtherScalar, DIM>& _rhs) {
|
||||||
|
std::transform(_rhs.data(), _rhs.data() + DIM,
|
||||||
|
data(), [](OtherScalar rhs) {
|
||||||
|
return static_cast<Scalar>(std::move(rhs));
|
||||||
|
});
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// access to Scalar array
|
||||||
|
Scalar* data() { return values_.data(); }
|
||||||
|
|
||||||
|
/// access to const Scalar array
|
||||||
|
const Scalar *data() const { return values_.data(); }
|
||||||
|
|
||||||
|
//----------------------------------------------------------- element access
|
||||||
|
|
||||||
|
/// get i'th element read-write
|
||||||
|
Scalar& operator[](size_t _i) {
|
||||||
|
assert(_i < DIM);
|
||||||
|
return values_[_i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// get i'th element read-only
|
||||||
|
const Scalar& operator[](size_t _i) const {
|
||||||
|
assert(_i < DIM);
|
||||||
|
return values_[_i];
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------- comparsion
|
||||||
|
|
||||||
|
/// component-wise comparison
|
||||||
|
bool operator==(const vector_type& _rhs) const {
|
||||||
|
return std::equal(_rhs.values_.cbegin(), _rhs.values_.cend(), values_.cbegin());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// component-wise comparison
|
||||||
|
bool operator!=(const vector_type& _rhs) const {
|
||||||
|
return !std::equal(_rhs.values_.cbegin(), _rhs.values_.cend(), values_.cbegin());
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------- scalar operators
|
||||||
|
|
||||||
|
/// component-wise self-multiplication with scalar
|
||||||
|
template<typename OtherScalar>
|
||||||
|
auto operator*=(const OtherScalar& _s) ->
|
||||||
|
typename std::enable_if<std::is_convertible<
|
||||||
|
decltype(this->values_[0] * _s), Scalar>::value,
|
||||||
|
VectorT<Scalar, DIM>&>::type {
|
||||||
|
for (auto& e : *this) {
|
||||||
|
e *= _s;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// component-wise self-division by scalar
|
||||||
|
template<typename OtherScalar>
|
||||||
|
auto operator/=(const OtherScalar& _s) ->
|
||||||
|
typename std::enable_if<std::is_convertible<
|
||||||
|
decltype(this->values_[0] / _s), Scalar>::value,
|
||||||
|
VectorT<Scalar, DIM>&>::type {
|
||||||
|
for (auto& e : *this) {
|
||||||
|
e /= _s;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// component-wise multiplication with scalar
|
||||||
|
template<typename OtherScalar>
|
||||||
|
typename std::enable_if<std::is_convertible<
|
||||||
|
decltype(std::declval<Scalar>() * std::declval<OtherScalar>()),
|
||||||
|
Scalar>::value,
|
||||||
|
VectorT<Scalar, DIM>>::type
|
||||||
|
operator*(const OtherScalar& _s) const {
|
||||||
|
return vector_type(*this) *= _s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// component-wise division by with scalar
|
||||||
|
template<typename OtherScalar>
|
||||||
|
typename std::enable_if<std::is_convertible<
|
||||||
|
decltype(std::declval<Scalar>() / std::declval<OtherScalar>()),
|
||||||
|
Scalar>::value,
|
||||||
|
VectorT<Scalar, DIM>>::type
|
||||||
|
operator/(const OtherScalar& _s) const {
|
||||||
|
return vector_type(*this) /= _s;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------- vector operators
|
||||||
|
|
||||||
|
/// component-wise self-multiplication
|
||||||
|
template<typename OtherScalar>
|
||||||
|
auto operator*=(const VectorT<OtherScalar, DIM>& _rhs) ->
|
||||||
|
typename std::enable_if<
|
||||||
|
sizeof(decltype(this->values_[0] * *_rhs.data())) >= 0,
|
||||||
|
vector_type&>::type {
|
||||||
|
for (int i = 0; i < DIM; ++i) {
|
||||||
|
data()[i] *= _rhs.data()[i];
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// component-wise self-division
|
||||||
|
template<typename OtherScalar>
|
||||||
|
auto operator/=(const VectorT<OtherScalar, DIM>& _rhs) ->
|
||||||
|
typename std::enable_if<
|
||||||
|
sizeof(decltype(this->values_[0] / *_rhs.data())) >= 0,
|
||||||
|
vector_type&>::type {
|
||||||
|
for (int i = 0; i < DIM; ++i) {
|
||||||
|
data()[i] /= _rhs.data()[i];
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// vector difference from this
|
||||||
|
template<typename OtherScalar>
|
||||||
|
auto operator-=(const VectorT<OtherScalar, DIM>& _rhs) ->
|
||||||
|
typename std::enable_if<
|
||||||
|
sizeof(decltype(this->values_[0] - *_rhs.data())) >= 0,
|
||||||
|
vector_type&>::type {
|
||||||
|
for (int i = 0; i < DIM; ++i) {
|
||||||
|
data()[i] -= _rhs.data()[i];
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// vector self-addition
|
||||||
|
template<typename OtherScalar>
|
||||||
|
auto operator+=(const VectorT<OtherScalar, DIM>& _rhs) ->
|
||||||
|
typename std::enable_if<
|
||||||
|
sizeof(decltype(this->values_[0] + *_rhs.data())) >= 0,
|
||||||
|
vector_type&>::type {
|
||||||
|
for (int i = 0; i < DIM; ++i) {
|
||||||
|
data()[i] += _rhs.data()[i];
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// component-wise vector multiplication
|
||||||
|
template<typename OtherScalar>
|
||||||
|
auto operator*(const VectorT<OtherScalar, DIM>& _rhs) const ->
|
||||||
|
typename std::enable_if<
|
||||||
|
sizeof(decltype(this->values_[0] * *_rhs.data())) >= 0,
|
||||||
|
vector_type>::type {
|
||||||
|
return vector_type(*this) *= _rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// component-wise vector division
|
||||||
|
template<typename OtherScalar>
|
||||||
|
auto operator/(const VectorT<OtherScalar, DIM>& _rhs) const ->
|
||||||
|
typename std::enable_if<
|
||||||
|
sizeof(decltype(this->values_[0] / *_rhs.data())) >= 0,
|
||||||
|
vector_type>::type {
|
||||||
|
return vector_type(*this) /= _rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// component-wise vector addition
|
||||||
|
template<typename OtherScalar>
|
||||||
|
auto operator+(const VectorT<OtherScalar, DIM>& _rhs) const ->
|
||||||
|
typename std::enable_if<
|
||||||
|
sizeof(decltype(this->values_[0] + *_rhs.data())) >= 0,
|
||||||
|
vector_type>::type {
|
||||||
|
return vector_type(*this) += _rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// component-wise vector difference
|
||||||
|
template<typename OtherScalar>
|
||||||
|
auto operator-(const VectorT<OtherScalar, DIM>& _rhs) const ->
|
||||||
|
typename std::enable_if<
|
||||||
|
sizeof(decltype(this->values_[0] - *_rhs.data())) >= 0,
|
||||||
|
vector_type>::type {
|
||||||
|
return vector_type(*this) -= _rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// unary minus
|
||||||
|
vector_type operator-(void) const {
|
||||||
|
vector_type v;
|
||||||
|
std::transform(values_.begin(), values_.end(), v.values_.begin(),
|
||||||
|
[](const Scalar &s) { return -s; });
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// cross product: only defined for Vec3* as specialization
|
||||||
|
/// \see OpenMesh::cross
|
||||||
|
template<typename OtherScalar>
|
||||||
|
auto operator% (const VectorT<OtherScalar, DIM> &_rhs) const ->
|
||||||
|
typename std::enable_if<DIM == 3,
|
||||||
|
VectorT<decltype(this->values_[0] * _rhs[0] -
|
||||||
|
this->values_[0] * _rhs[0]),
|
||||||
|
DIM>>::type {
|
||||||
|
return {
|
||||||
|
values_[1] * _rhs[2] - values_[2] * _rhs[1],
|
||||||
|
values_[2] * _rhs[0] - values_[0] * _rhs[2],
|
||||||
|
values_[0] * _rhs[1] - values_[1] * _rhs[0]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// compute scalar product
|
||||||
|
/// \see OpenMesh::dot
|
||||||
|
template<typename OtherScalar>
|
||||||
|
auto operator|(const VectorT<OtherScalar, DIM>& _rhs) const ->
|
||||||
|
decltype(*this->data() * *_rhs.data()) {
|
||||||
|
|
||||||
|
return std::inner_product(data() + 1, data() + DIM, _rhs.data() + 1,
|
||||||
|
*data() * *_rhs.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------ euclidean norm
|
||||||
|
|
||||||
|
/// \name Euclidean norm calculations
|
||||||
|
//@{
|
||||||
|
|
||||||
|
/// compute squared euclidean norm
|
||||||
|
template<typename S = Scalar>
|
||||||
|
decltype(std::declval<S>() * std::declval<S>()) sqrnorm() const {
|
||||||
|
static_assert(std::is_same<S, Scalar>::value, "S and Scalar need "
|
||||||
|
"to be the same type. (Never override the default template "
|
||||||
|
"arguments.)");
|
||||||
|
typedef decltype(values_[0] * values_[0]) RESULT;
|
||||||
|
return std::accumulate(values_.cbegin() + 1, values_.cend(),
|
||||||
|
values_[0] * values_[0],
|
||||||
|
[](const RESULT &l, const Scalar &r) { return l + r * r; });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// compute euclidean norm
|
||||||
|
template<typename S = Scalar>
|
||||||
|
auto norm() const ->
|
||||||
|
decltype(std::sqrt(std::declval<VectorT<S, DIM>>().sqrnorm())) {
|
||||||
|
static_assert(std::is_same<S, Scalar>::value, "S and Scalar need "
|
||||||
|
"to be the same type. (Never override the default template "
|
||||||
|
"arguments.)");
|
||||||
|
return std::sqrt(sqrnorm());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename S = Scalar>
|
||||||
|
auto length() const ->
|
||||||
|
decltype(std::declval<VectorT<S, DIM>>().norm()) {
|
||||||
|
static_assert(std::is_same<S, Scalar>::value, "S and Scalar need "
|
||||||
|
"to be the same type. (Never override the default template "
|
||||||
|
"arguments.)");
|
||||||
|
return norm();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** normalize vector, return normalized vector
|
||||||
|
*/
|
||||||
|
template<typename S = Scalar>
|
||||||
|
auto normalize() ->
|
||||||
|
decltype(*this /= std::declval<VectorT<S, DIM>>().norm()) {
|
||||||
|
static_assert(std::is_same<S, Scalar>::value, "S and Scalar need "
|
||||||
|
"to be the same type. (Never override the default template "
|
||||||
|
"arguments.)");
|
||||||
|
return *this /= norm();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** return normalized vector
|
||||||
|
*/
|
||||||
|
template<typename S = Scalar>
|
||||||
|
auto normalized() const ->
|
||||||
|
decltype(*this / std::declval<VectorT<S, DIM>>().norm()) {
|
||||||
|
static_assert(std::is_same<S, Scalar>::value, "S and Scalar need "
|
||||||
|
"to be the same type. (Never override the default template "
|
||||||
|
"arguments.)");
|
||||||
|
return *this / norm();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** normalize vector, return normalized vector and avoids div by zero
|
||||||
|
*/
|
||||||
|
template<typename S = Scalar>
|
||||||
|
typename std::enable_if<
|
||||||
|
sizeof(decltype(
|
||||||
|
static_cast<S>(0),
|
||||||
|
std::declval<VectorT<S, DIM>>().norm())) >= 0,
|
||||||
|
vector_type&>::type
|
||||||
|
normalize_cond() {
|
||||||
|
static_assert(std::is_same<S, Scalar>::value, "S and Scalar need "
|
||||||
|
"to be the same type. (Never override the default template "
|
||||||
|
"arguments.)");
|
||||||
|
auto n = norm();
|
||||||
|
if (n != static_cast<decltype(norm())>(0)) {
|
||||||
|
*this /= n;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
//------------------------------------------------------------ euclidean norm
|
||||||
|
|
||||||
|
/// \name Non-Euclidean norm calculations
|
||||||
|
//@{
|
||||||
|
|
||||||
|
/// compute L1 (Manhattan) norm
|
||||||
|
Scalar l1_norm() const {
|
||||||
|
return std::accumulate(
|
||||||
|
values_.cbegin() + 1, values_.end(), values_[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// compute l8_norm
|
||||||
|
Scalar l8_norm() const {
|
||||||
|
return max_abs();
|
||||||
|
}
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
//------------------------------------------------------------ max, min, mean
|
||||||
|
|
||||||
|
/// \name Minimum maximum and mean
|
||||||
|
//@{
|
||||||
|
|
||||||
|
/// return the maximal component
|
||||||
|
Scalar max() const {
|
||||||
|
return *std::max_element(values_.cbegin(), values_.cend());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// return the maximal absolute component
|
||||||
|
Scalar max_abs() const {
|
||||||
|
return std::abs(
|
||||||
|
*std::max_element(values_.cbegin(), values_.cend(),
|
||||||
|
[](const Scalar &a, const Scalar &b) {
|
||||||
|
return std::abs(a) < std::abs(b);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// return the minimal component
|
||||||
|
Scalar min() const {
|
||||||
|
return *std::min_element(values_.cbegin(), values_.cend());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// return the minimal absolute component
|
||||||
|
Scalar min_abs() const {
|
||||||
|
return std::abs(
|
||||||
|
*std::min_element(values_.cbegin(), values_.cend(),
|
||||||
|
[](const Scalar &a, const Scalar &b) {
|
||||||
|
return std::abs(a) < std::abs(b);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// return arithmetic mean
|
||||||
|
Scalar mean() const {
|
||||||
|
return l1_norm()/DIM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// return absolute arithmetic mean
|
||||||
|
Scalar mean_abs() const {
|
||||||
|
return std::accumulate(values_.cbegin() + 1, values_.end(),
|
||||||
|
std::abs(values_[0]),
|
||||||
|
[](const Scalar &l, const Scalar &r) {
|
||||||
|
return l + std::abs(r);
|
||||||
|
}) / DIM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// minimize values: same as *this = min(*this, _rhs), but faster
|
||||||
|
vector_type& minimize(const vector_type& _rhs) {
|
||||||
|
std::transform(values_.cbegin(), values_.cend(),
|
||||||
|
_rhs.values_.cbegin(),
|
||||||
|
values_.begin(),
|
||||||
|
[](const Scalar &l, const Scalar &r) {
|
||||||
|
return std::min(l, r);
|
||||||
|
});
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// minimize values and signalize coordinate minimization
|
||||||
|
bool minimized(const vector_type& _rhs) {
|
||||||
|
bool result = false;
|
||||||
|
std::transform(values_.cbegin(), values_.cend(),
|
||||||
|
_rhs.values_.cbegin(),
|
||||||
|
values_.begin(),
|
||||||
|
[&result](const Scalar &l, const Scalar &r) {
|
||||||
|
if (l < r) {
|
||||||
|
return l;
|
||||||
|
} else {
|
||||||
|
result = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// maximize values: same as *this = max(*this, _rhs), but faster
|
||||||
|
vector_type& maximize(const vector_type& _rhs) {
|
||||||
|
std::transform(values_.cbegin(), values_.cend(),
|
||||||
|
_rhs.values_.cbegin(),
|
||||||
|
values_.begin(),
|
||||||
|
[](const Scalar &l, const Scalar &r) {
|
||||||
|
return std::max(l, r);
|
||||||
|
});
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// maximize values and signalize coordinate maximization
|
||||||
|
bool maximized(const vector_type& _rhs) {
|
||||||
|
bool result = false;
|
||||||
|
std::transform(values_.cbegin(), values_.cend(),
|
||||||
|
_rhs.values_.cbegin(),
|
||||||
|
values_.begin(),
|
||||||
|
[&result](const Scalar &l, const Scalar &r) {
|
||||||
|
if (l > r) {
|
||||||
|
return l;
|
||||||
|
} else {
|
||||||
|
result = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// component-wise min
|
||||||
|
inline vector_type min(const vector_type& _rhs) const {
|
||||||
|
return vector_type(*this).minimize(_rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// component-wise max
|
||||||
|
inline vector_type max(const vector_type& _rhs) const {
|
||||||
|
return vector_type(*this).maximize(_rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
//------------------------------------------------------------ misc functions
|
||||||
|
|
||||||
|
/// component-wise apply function object with Scalar operator()(Scalar).
|
||||||
|
template<typename Functor>
|
||||||
|
inline vector_type apply(const Functor& _func) const {
|
||||||
|
vector_type result;
|
||||||
|
std::transform(result.values_.begin(), result.values_.end(),
|
||||||
|
result.values_.begin(), _func);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// store the same value in each component (e.g. to clear all entries)
|
||||||
|
vector_type& vectorize(const Scalar& _s) {
|
||||||
|
std::fill(values_.begin(), values_.end(), _s);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// store the same value in each component
|
||||||
|
static vector_type vectorized(const Scalar& _s) {
|
||||||
|
return vector_type().vectorize(_s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// lexicographical comparison
|
||||||
|
bool operator<(const vector_type& _rhs) const {
|
||||||
|
return std::lexicographical_compare(
|
||||||
|
values_.begin(), values_.end(),
|
||||||
|
_rhs.values_.begin(), _rhs.values_.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------ component iterators
|
||||||
|
|
||||||
|
/// \name Component iterators
|
||||||
|
//@{
|
||||||
|
|
||||||
|
using iterator = typename container::iterator;
|
||||||
|
using const_iterator = typename container::const_iterator;
|
||||||
|
using reverse_iterator = typename container::reverse_iterator;
|
||||||
|
using const_reverse_iterator = typename container::const_reverse_iterator;
|
||||||
|
|
||||||
|
iterator begin() noexcept { return values_.begin(); }
|
||||||
|
const_iterator begin() const noexcept { return values_.cbegin(); }
|
||||||
|
const_iterator cbegin() const noexcept { return values_.cbegin(); }
|
||||||
|
|
||||||
|
iterator end() noexcept { return values_.end(); }
|
||||||
|
const_iterator end() const noexcept { return values_.cend(); }
|
||||||
|
const_iterator cend() const noexcept { return values_.cend(); }
|
||||||
|
|
||||||
|
reverse_iterator rbegin() noexcept { return values_.rbegin(); }
|
||||||
|
const_reverse_iterator rbegin() const noexcept { return values_.crbegin(); }
|
||||||
|
const_reverse_iterator crbegin() const noexcept { return values_.crbegin(); }
|
||||||
|
|
||||||
|
reverse_iterator rend() noexcept { return values_.rend(); }
|
||||||
|
const_reverse_iterator rend() const noexcept { return values_.crend(); }
|
||||||
|
const_reverse_iterator crend() const noexcept { return values_.crend(); }
|
||||||
|
|
||||||
|
//@}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Component wise multiplication from the left
|
||||||
|
template<typename Scalar, int DIM, typename OtherScalar>
|
||||||
|
auto operator*(const OtherScalar& _s, const VectorT<Scalar, DIM> &rhs) ->
|
||||||
|
decltype(rhs.operator*(_s)) {
|
||||||
|
|
||||||
|
return rhs * _s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// output a vector by printing its space-separated compontens
|
||||||
|
template<typename Scalar, int DIM>
|
||||||
|
auto operator<<(std::ostream& os, const VectorT<Scalar, DIM> &_vec) ->
|
||||||
|
typename std::enable_if<
|
||||||
|
sizeof(decltype(os << _vec[0])) >= 0, std::ostream&>::type {
|
||||||
|
|
||||||
|
os << _vec[0];
|
||||||
|
for (int i = 1; i < DIM; ++i) {
|
||||||
|
os << " " << _vec[i];
|
||||||
|
}
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// read the space-separated components of a vector from a stream
|
||||||
|
template<typename Scalar, int DIM>
|
||||||
|
auto operator>> (std::istream& is, VectorT<Scalar, DIM> &_vec) ->
|
||||||
|
typename std::enable_if<
|
||||||
|
sizeof(decltype(is >> _vec[0])) >= 0, std::istream &>::type {
|
||||||
|
for (int i = 0; i < DIM; ++i)
|
||||||
|
is >> _vec[i];
|
||||||
|
return is;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \relates OpenMesh::VectorT
|
||||||
|
/// symmetric version of the dot product
|
||||||
|
template<typename Scalar, int DIM>
|
||||||
|
Scalar dot(const VectorT<Scalar, DIM>& _v1, const VectorT<Scalar, DIM>& _v2) {
|
||||||
|
return (_v1 | _v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// \relates OpenMesh::VectorT
|
||||||
|
/// symmetric version of the cross product
|
||||||
|
template<typename LScalar, typename RScalar, int DIM>
|
||||||
|
auto
|
||||||
|
cross(const VectorT<LScalar, DIM>& _v1, const VectorT<RScalar, DIM>& _v2) ->
|
||||||
|
decltype(_v1 % _v2) {
|
||||||
|
return (_v1 % _v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//== TYPEDEFS =================================================================
|
||||||
|
|
||||||
|
/** 1-byte signed vector */
|
||||||
|
typedef VectorT<signed char,1> Vec1c;
|
||||||
|
/** 1-byte unsigned vector */
|
||||||
|
typedef VectorT<unsigned char,1> Vec1uc;
|
||||||
|
/** 1-short signed vector */
|
||||||
|
typedef VectorT<signed short int,1> Vec1s;
|
||||||
|
/** 1-short unsigned vector */
|
||||||
|
typedef VectorT<unsigned short int,1> Vec1us;
|
||||||
|
/** 1-int signed vector */
|
||||||
|
typedef VectorT<signed int,1> Vec1i;
|
||||||
|
/** 1-int unsigned vector */
|
||||||
|
typedef VectorT<unsigned int,1> Vec1ui;
|
||||||
|
/** 1-float vector */
|
||||||
|
typedef VectorT<float,1> Vec1f;
|
||||||
|
/** 1-double vector */
|
||||||
|
typedef VectorT<double,1> Vec1d;
|
||||||
|
|
||||||
|
/** 2-byte signed vector */
|
||||||
|
typedef VectorT<signed char,2> Vec2c;
|
||||||
|
/** 2-byte unsigned vector */
|
||||||
|
typedef VectorT<unsigned char,2> Vec2uc;
|
||||||
|
/** 2-short signed vector */
|
||||||
|
typedef VectorT<signed short int,2> Vec2s;
|
||||||
|
/** 2-short unsigned vector */
|
||||||
|
typedef VectorT<unsigned short int,2> Vec2us;
|
||||||
|
/** 2-int signed vector */
|
||||||
|
typedef VectorT<signed int,2> Vec2i;
|
||||||
|
/** 2-int unsigned vector */
|
||||||
|
typedef VectorT<unsigned int,2> Vec2ui;
|
||||||
|
/** 2-float vector */
|
||||||
|
typedef VectorT<float,2> Vec2f;
|
||||||
|
/** 2-double vector */
|
||||||
|
typedef VectorT<double,2> Vec2d;
|
||||||
|
|
||||||
|
/** 3-byte signed vector */
|
||||||
|
typedef VectorT<signed char,3> Vec3c;
|
||||||
|
/** 3-byte unsigned vector */
|
||||||
|
typedef VectorT<unsigned char,3> Vec3uc;
|
||||||
|
/** 3-short signed vector */
|
||||||
|
typedef VectorT<signed short int,3> Vec3s;
|
||||||
|
/** 3-short unsigned vector */
|
||||||
|
typedef VectorT<unsigned short int,3> Vec3us;
|
||||||
|
/** 3-int signed vector */
|
||||||
|
typedef VectorT<signed int,3> Vec3i;
|
||||||
|
/** 3-int unsigned vector */
|
||||||
|
typedef VectorT<unsigned int,3> Vec3ui;
|
||||||
|
/** 3-float vector */
|
||||||
|
typedef VectorT<float,3> Vec3f;
|
||||||
|
/** 3-double vector */
|
||||||
|
typedef VectorT<double,3> Vec3d;
|
||||||
|
/** 3-bool vector */
|
||||||
|
typedef VectorT<bool,3> Vec3b;
|
||||||
|
|
||||||
|
/** 4-byte signed vector */
|
||||||
|
typedef VectorT<signed char,4> Vec4c;
|
||||||
|
/** 4-byte unsigned vector */
|
||||||
|
typedef VectorT<unsigned char,4> Vec4uc;
|
||||||
|
/** 4-short signed vector */
|
||||||
|
typedef VectorT<signed short int,4> Vec4s;
|
||||||
|
/** 4-short unsigned vector */
|
||||||
|
typedef VectorT<unsigned short int,4> Vec4us;
|
||||||
|
/** 4-int signed vector */
|
||||||
|
typedef VectorT<signed int,4> Vec4i;
|
||||||
|
/** 4-int unsigned vector */
|
||||||
|
typedef VectorT<unsigned int,4> Vec4ui;
|
||||||
|
/** 4-float vector */
|
||||||
|
typedef VectorT<float,4> Vec4f;
|
||||||
|
/** 4-double vector */
|
||||||
|
typedef VectorT<double,4> Vec4d;
|
||||||
|
|
||||||
|
/** 5-byte signed vector */
|
||||||
|
typedef VectorT<signed char, 5> Vec5c;
|
||||||
|
/** 5-byte unsigned vector */
|
||||||
|
typedef VectorT<unsigned char, 5> Vec5uc;
|
||||||
|
/** 5-short signed vector */
|
||||||
|
typedef VectorT<signed short int, 5> Vec5s;
|
||||||
|
/** 5-short unsigned vector */
|
||||||
|
typedef VectorT<unsigned short int, 5> Vec5us;
|
||||||
|
/** 5-int signed vector */
|
||||||
|
typedef VectorT<signed int, 5> Vec5i;
|
||||||
|
/** 5-int unsigned vector */
|
||||||
|
typedef VectorT<unsigned int, 5> Vec5ui;
|
||||||
|
/** 5-float vector */
|
||||||
|
typedef VectorT<float, 5> Vec5f;
|
||||||
|
/** 5-double vector */
|
||||||
|
typedef VectorT<double, 5> Vec5d;
|
||||||
|
|
||||||
|
/** 6-byte signed vector */
|
||||||
|
typedef VectorT<signed char,6> Vec6c;
|
||||||
|
/** 6-byte unsigned vector */
|
||||||
|
typedef VectorT<unsigned char,6> Vec6uc;
|
||||||
|
/** 6-short signed vector */
|
||||||
|
typedef VectorT<signed short int,6> Vec6s;
|
||||||
|
/** 6-short unsigned vector */
|
||||||
|
typedef VectorT<unsigned short int,6> Vec6us;
|
||||||
|
/** 6-int signed vector */
|
||||||
|
typedef VectorT<signed int,6> Vec6i;
|
||||||
|
/** 6-int unsigned vector */
|
||||||
|
typedef VectorT<unsigned int,6> Vec6ui;
|
||||||
|
/** 6-float vector */
|
||||||
|
typedef VectorT<float,6> Vec6f;
|
||||||
|
/** 6-double vector */
|
||||||
|
typedef VectorT<double,6> Vec6d;
|
||||||
|
|
||||||
|
} // namespace OpenMesh
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Literal operator for inline specification of colors in HTML syntax.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* \code{.cpp}
|
||||||
|
* OpenMesh::Vec4f light_blue = 0x1FCFFFFF_htmlColor;
|
||||||
|
* \endcode
|
||||||
|
*/
|
||||||
|
constexpr OpenMesh::Vec4f operator"" _htmlColor(unsigned long long raw_color) {
|
||||||
|
return OpenMesh::Vec4f(
|
||||||
|
((raw_color >> 24) & 0xFF) / 255.0f,
|
||||||
|
((raw_color >> 16) & 0xFF) / 255.0f,
|
||||||
|
((raw_color >> 8) & 0xFF) / 255.0f,
|
||||||
|
((raw_color >> 0) & 0xFF) / 255.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* OPENMESH_SRC_OPENMESH_CORE_GEOMETRY_VECTOR11T_HH_ */
|
||||||
@@ -59,6 +59,10 @@
|
|||||||
// bugreport: https://bugzilla.gnome.org/show_bug.cgi?id=629182)
|
// bugreport: https://bugzilla.gnome.org/show_bug.cgi?id=629182)
|
||||||
// macro expansion and preprocessor defines
|
// macro expansion and preprocessor defines
|
||||||
// don't work properly.
|
// don't work properly.
|
||||||
|
|
||||||
|
#if (__cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(OPENMESH_VECTOR_LEGACY)
|
||||||
|
#include "Vector11T.hh"
|
||||||
|
#else
|
||||||
#ifndef DOXYGEN
|
#ifndef DOXYGEN
|
||||||
|
|
||||||
#ifndef OPENMESH_VECTOR_HH
|
#ifndef OPENMESH_VECTOR_HH
|
||||||
@@ -77,12 +81,6 @@
|
|||||||
#include <xmmintrin.h>
|
#include <xmmintrin.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
|
||||||
#include <array>
|
|
||||||
#include <initializer_list>
|
|
||||||
#include <type_traits>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//== NAMESPACES ===============================================================
|
//== NAMESPACES ===============================================================
|
||||||
|
|
||||||
|
|
||||||
@@ -92,24 +90,6 @@ namespace OpenMesh {
|
|||||||
//== CLASS DEFINITION =========================================================
|
//== CLASS DEFINITION =========================================================
|
||||||
|
|
||||||
|
|
||||||
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
|
||||||
/*
|
|
||||||
* Helpers for VectorT
|
|
||||||
*/
|
|
||||||
namespace {
|
|
||||||
template<typename... Ts>
|
|
||||||
struct are_convertible_to;
|
|
||||||
|
|
||||||
template<typename To, typename From, typename... Froms>
|
|
||||||
struct are_convertible_to<To, From, Froms...> {
|
|
||||||
static constexpr bool value = std::is_convertible<From, To>::value && are_convertible_to<To, Froms...>::value;
|
|
||||||
};
|
|
||||||
template<typename To, typename From>
|
|
||||||
struct are_convertible_to<To, From> : public std::is_convertible<From, To> {};
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/** The N values of the template Scalar type are the only data members
|
/** The N values of the template Scalar type are the only data members
|
||||||
of the class VectorT<Scalar,N>. This guarantees 100% compatibility
|
of the class VectorT<Scalar,N>. This guarantees 100% compatibility
|
||||||
with arrays of type Scalar and size N, allowing us to define the
|
with arrays of type Scalar and size N, allowing us to define the
|
||||||
@@ -121,18 +101,7 @@ struct are_convertible_to<To, From> : public std::is_convertible<From, To> {};
|
|||||||
*/
|
*/
|
||||||
template<typename Scalar, int N> class VectorDataT {
|
template<typename Scalar, int N> class VectorDataT {
|
||||||
public:
|
public:
|
||||||
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
|
||||||
VectorDataT() {}
|
|
||||||
|
|
||||||
template<typename... T>
|
|
||||||
constexpr VectorDataT(T... vs) : values_ {{vs...}} {
|
|
||||||
static_assert(sizeof...(vs) == N,
|
|
||||||
"Incorrect number of vector components supplied.");
|
|
||||||
}
|
|
||||||
std::array<Scalar, N> values_;
|
|
||||||
#else
|
|
||||||
Scalar values_[N];
|
Scalar values_[N];
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -141,22 +110,9 @@ template<typename Scalar, int N> class VectorDataT {
|
|||||||
/// This specialization enables us to use aligned SSE instructions.
|
/// This specialization enables us to use aligned SSE instructions.
|
||||||
template<> class VectorDataT<float, 4> {
|
template<> class VectorDataT<float, 4> {
|
||||||
public:
|
public:
|
||||||
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
|
||||||
VectorDataT() {}
|
|
||||||
|
|
||||||
template<typename... T>
|
|
||||||
constexpr VectorDataT(T... vs) : values_ {{vs...}} {
|
|
||||||
static_assert(sizeof...(vs) == 4,
|
|
||||||
"Incorrect number of vector components supplied.");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
union {
|
union {
|
||||||
__m128 m128;
|
__m128 m128;
|
||||||
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
|
||||||
std::array<float, 4> values_;
|
|
||||||
#else
|
|
||||||
float values_[4];
|
float values_[4];
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -432,24 +388,7 @@ typedef VectorT<double,6> Vec6d;
|
|||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
|
|
||||||
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
|
||||||
/**
|
|
||||||
* Literal operator for inline specification of colors in HTML syntax.
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
* \code{.cpp}
|
|
||||||
* OpenMesh::Vec4f light_blue = 0x1FCFFFFF_htmlColor;
|
|
||||||
* \endcode
|
|
||||||
*/
|
|
||||||
constexpr OpenMesh::Vec4f operator"" _htmlColor(unsigned long long raw_color) {
|
|
||||||
return OpenMesh::Vec4f(
|
|
||||||
((raw_color >> 24) & 0xFF) / 255.0f,
|
|
||||||
((raw_color >> 16) & 0xFF) / 255.0f,
|
|
||||||
((raw_color >> 8) & 0xFF) / 255.0f,
|
|
||||||
((raw_color >> 0) & 0xFF) / 255.0f);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // OPENMESH_VECTOR_HH defined
|
#endif // OPENMESH_VECTOR_HH defined
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
#endif // DOXYGEN
|
#endif // DOXYGEN
|
||||||
|
#endif // C++11
|
||||||
|
|||||||
@@ -97,28 +97,6 @@ public:
|
|||||||
/// default constructor creates uninitialized values.
|
/// default constructor creates uninitialized values.
|
||||||
inline VectorT() {}
|
inline VectorT() {}
|
||||||
|
|
||||||
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
|
||||||
explicit inline VectorT(const Scalar &v) {
|
|
||||||
vectorize(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... T,
|
|
||||||
typename = typename std::enable_if<sizeof...(T) == DIM>::type,
|
|
||||||
typename = typename std::enable_if<are_convertible_to<Scalar, T...>::value>::type>
|
|
||||||
constexpr VectorT(T... vs) : Base { static_cast<Scalar>(vs)...}
|
|
||||||
{ }
|
|
||||||
|
|
||||||
template<int D = DIM, typename = typename std::enable_if<D == DIM>::type>
|
|
||||||
typename std::enable_if<D==4, VectorT>::type
|
|
||||||
homogenized() const {
|
|
||||||
return VectorT(
|
|
||||||
Base::values_[0]/Base::values_[3],
|
|
||||||
Base::values_[1]/Base::values_[3],
|
|
||||||
Base::values_[2]/Base::values_[3],
|
|
||||||
1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
/// special constructor for 1D vectors
|
/// special constructor for 1D vectors
|
||||||
explicit inline VectorT(const Scalar& v) {
|
explicit inline VectorT(const Scalar& v) {
|
||||||
// assert(DIM==1);
|
// assert(DIM==1);
|
||||||
@@ -165,7 +143,6 @@ public:
|
|||||||
Base::values_[0]=v0; Base::values_[1]=v1; Base::values_[2]=v2;
|
Base::values_[0]=v0; Base::values_[1]=v1; Base::values_[2]=v2;
|
||||||
Base::values_[3]=v3; Base::values_[4]=v4; Base::values_[5]=v5;
|
Base::values_[3]=v3; Base::values_[4]=v4; Base::values_[5]=v5;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// construct from a value array (explicit)
|
/// construct from a value array (explicit)
|
||||||
@@ -210,21 +187,11 @@ public:
|
|||||||
// /// cast to const Scalar array
|
// /// cast to const Scalar array
|
||||||
// inline operator const Scalar*() const { return Base::values_; }
|
// inline operator const Scalar*() const { return Base::values_; }
|
||||||
|
|
||||||
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
|
||||||
/// access to Scalar array
|
|
||||||
inline Scalar* data() { return Base::values_.data(); }
|
|
||||||
|
|
||||||
/// access to const Scalar array
|
|
||||||
inline const Scalar*data() const { return Base::values_.data(); }
|
|
||||||
#else
|
|
||||||
/// access to Scalar array
|
/// access to Scalar array
|
||||||
inline Scalar* data() { return Base::values_; }
|
inline Scalar* data() { return Base::values_; }
|
||||||
|
|
||||||
/// access to const Scalar array
|
/// access to const Scalar array
|
||||||
inline const Scalar*data() const { return Base::values_; }
|
inline const Scalar*data() const { return Base::values_; }
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------- element access
|
//----------------------------------------------------------- element access
|
||||||
|
|||||||
@@ -38,6 +38,71 @@ Scalar get_item(Vector& _vec, int _index) {
|
|||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
template<class Scalar>
|
||||||
|
struct Factory {
|
||||||
|
typedef OpenMesh::VectorT<Scalar, 2> Vector2;
|
||||||
|
typedef OpenMesh::VectorT<Scalar, 3> Vector3;
|
||||||
|
typedef OpenMesh::VectorT<Scalar, 4> Vector4;
|
||||||
|
|
||||||
|
static Vector2 *vec2_default() {
|
||||||
|
return new Vector2(Scalar(), Scalar());
|
||||||
|
}
|
||||||
|
static Vector2 *vec2_user_defined(const Scalar& _v0, const Scalar& _v1) {
|
||||||
|
return new Vector2(_v0, _v1);
|
||||||
|
}
|
||||||
|
static Vector3 *vec3_default() {
|
||||||
|
return new Vector3(Scalar(), Scalar(), Scalar());
|
||||||
|
}
|
||||||
|
static Vector3 *vec3_user_defined(const Scalar& _v0, const Scalar& _v1, const Scalar& _v2) {
|
||||||
|
return new Vector3(_v0, _v1, _v2);
|
||||||
|
}
|
||||||
|
static Vector4 *vec4_default() {
|
||||||
|
return new Vector4(Scalar(), Scalar(), Scalar(), Scalar());
|
||||||
|
}
|
||||||
|
static Vector4 *vec4_user_defined(const Scalar& _v0, const Scalar& _v1, const Scalar& _v2, const Scalar& _v3) {
|
||||||
|
return new Vector4(_v0, _v1, _v2, _v3);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Scalar, int N>
|
||||||
|
void defInitMod(class_<OpenMesh::VectorT<Scalar, N>> &classVector);
|
||||||
|
|
||||||
|
template<class Scalar>
|
||||||
|
void defInitMod(class_<OpenMesh::VectorT<Scalar, 2>> &classVector) {
|
||||||
|
classVector
|
||||||
|
.def("__init__", make_constructor(&Factory<Scalar>::vec2_default))
|
||||||
|
.def("__init__", make_constructor(&Factory<Scalar>::vec2_user_defined))
|
||||||
|
;
|
||||||
|
|
||||||
|
typedef OpenMesh::VectorT<Scalar, 2> Vector;
|
||||||
|
def("dot", &Vector::operator|);
|
||||||
|
}
|
||||||
|
template<class Scalar>
|
||||||
|
void defInitMod(class_<OpenMesh::VectorT<Scalar, 3>> &classVector) {
|
||||||
|
classVector
|
||||||
|
.def("__init__", make_constructor(&Factory<Scalar>::vec3_default))
|
||||||
|
.def("__init__", make_constructor(&Factory<Scalar>::vec3_user_defined))
|
||||||
|
.def("__mod__", &Factory<Scalar>::Vector3::operator%)
|
||||||
|
;
|
||||||
|
|
||||||
|
def("cross", &Factory<Scalar>::Vector3::operator%);
|
||||||
|
|
||||||
|
typedef OpenMesh::VectorT<Scalar, 3> Vector;
|
||||||
|
def("dot", &Vector::operator|);
|
||||||
|
}
|
||||||
|
template<class Scalar>
|
||||||
|
void defInitMod(class_<OpenMesh::VectorT<Scalar, 4>> &classVector) {
|
||||||
|
classVector
|
||||||
|
.def("__init__", make_constructor(&Factory<Scalar>::vec4_default))
|
||||||
|
.def("__init__", make_constructor(&Factory<Scalar>::vec4_user_defined))
|
||||||
|
;
|
||||||
|
|
||||||
|
typedef OpenMesh::VectorT<Scalar, 4> Vector;
|
||||||
|
def("dot", &Vector::operator|);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expose a vector type to %Python.
|
* Expose a vector type to %Python.
|
||||||
*
|
*
|
||||||
@@ -86,12 +151,12 @@ void expose_vec(const char *_name) {
|
|||||||
.def("vectorize", &Vector::vectorize, return_internal_reference<>())
|
.def("vectorize", &Vector::vectorize, return_internal_reference<>())
|
||||||
.def(self < self)
|
.def(self < self)
|
||||||
|
|
||||||
.def("norm", &Vector::norm)
|
.def("norm", &Vector::template norm<Scalar>)
|
||||||
.def("length", &Vector::length)
|
.def("length", &Vector::template length<Scalar>)
|
||||||
.def("sqrnorm", &Vector::sqrnorm)
|
.def("sqrnorm", &Vector::template sqrnorm<Scalar>)
|
||||||
.def("normalize", &Vector::normalize, return_internal_reference<>())
|
.def("normalize", &Vector::template normalize<Scalar>, return_internal_reference<>())
|
||||||
.def("normalized", &Vector::normalized)
|
.def("normalized", &Vector::template normalized<Scalar>)
|
||||||
.def("normalize_cond", &Vector::normalize_cond, return_internal_reference<>())
|
.def("normalize_cond", &Vector::template normalize_cond<Scalar>, return_internal_reference<>())
|
||||||
|
|
||||||
.def("l1_norm", &Vector::l1_norm)
|
.def("l1_norm", &Vector::l1_norm)
|
||||||
.def("l8_norm", &Vector::l8_norm)
|
.def("l8_norm", &Vector::l8_norm)
|
||||||
@@ -115,56 +180,7 @@ void expose_vec(const char *_name) {
|
|||||||
.staticmethod("vectorized")
|
.staticmethod("vectorized")
|
||||||
;
|
;
|
||||||
|
|
||||||
typedef OpenMesh::VectorT<Scalar, 2> Vector2;
|
defInitMod<Scalar, N>(classVector);
|
||||||
typedef OpenMesh::VectorT<Scalar, 3> Vector3;
|
|
||||||
typedef OpenMesh::VectorT<Scalar, 4> Vector4;
|
|
||||||
|
|
||||||
struct Factory {
|
|
||||||
static Vector2 *vec2_default() {
|
|
||||||
return new Vector2(Scalar(), Scalar());
|
|
||||||
}
|
|
||||||
static Vector2 *vec2_user_defined(const Scalar& _v0, const Scalar& _v1) {
|
|
||||||
return new Vector2(_v0, _v1);
|
|
||||||
}
|
|
||||||
static Vector3 *vec3_default() {
|
|
||||||
return new Vector3(Scalar(), Scalar(), Scalar());
|
|
||||||
}
|
|
||||||
static Vector3 *vec3_user_defined(const Scalar& _v0, const Scalar& _v1, const Scalar& _v2) {
|
|
||||||
return new Vector3(_v0, _v1, _v2);
|
|
||||||
}
|
|
||||||
static Vector4 *vec4_default() {
|
|
||||||
return new Vector4(Scalar(), Scalar(), Scalar(), Scalar());
|
|
||||||
}
|
|
||||||
static Vector4 *vec4_user_defined(const Scalar& _v0, const Scalar& _v1, const Scalar& _v2, const Scalar& _v3) {
|
|
||||||
return new Vector4(_v0, _v1, _v2, _v3);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (N == 2) {
|
|
||||||
classVector
|
|
||||||
.def("__init__", make_constructor(&Factory::vec2_default))
|
|
||||||
.def("__init__", make_constructor(&Factory::vec2_user_defined))
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (N == 3) {
|
|
||||||
classVector
|
|
||||||
.def("__init__", make_constructor(&Factory::vec3_default))
|
|
||||||
.def("__init__", make_constructor(&Factory::vec3_user_defined))
|
|
||||||
.def("__mod__", &Vector3::operator%)
|
|
||||||
;
|
|
||||||
|
|
||||||
def("cross", &Vector3::operator%);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (N == 4) {
|
|
||||||
classVector
|
|
||||||
.def("__init__", make_constructor(&Factory::vec4_default))
|
|
||||||
.def("__init__", make_constructor(&Factory::vec4_user_defined))
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
def("dot", &Vector::operator|);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace OpenMesh
|
} // namespace OpenMesh
|
||||||
|
|||||||
7
src/Unittests/.gitignore
vendored
Normal file
7
src/Unittests/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
deleted_output.off
|
||||||
|
output.off
|
||||||
|
persistence-check.om
|
||||||
|
smoothed_STL_output.off
|
||||||
|
smoothed_custom_properties_output.off
|
||||||
|
smoothed_extended_output.off
|
||||||
|
smoothed_output.off
|
||||||
6
src/Unittests/TestFiles/.gitignore
vendored
Normal file
6
src/Unittests/TestFiles/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
cube-minimal-customprops_openmeshOutputTestfileBinary.ply
|
||||||
|
cube_floating.off
|
||||||
|
cube_floating_binary.off
|
||||||
|
meshlab_binary.ply
|
||||||
|
meshlab_binary_float.ply
|
||||||
|
meshlab_float.ply
|
||||||
@@ -82,6 +82,7 @@ TEST_F(OpenMesh_Triangle, cpp11_vertexrange_test) {
|
|||||||
for(Mesh::VertexHandle t : mesh_.vertices())
|
for(Mesh::VertexHandle t : mesh_.vertices())
|
||||||
{
|
{
|
||||||
FAIL() << "The Vertexrange for an empty Mesh is not empty";
|
FAIL() << "The Vertexrange for an empty Mesh is not empty";
|
||||||
|
EXPECT_TRUE(t.is_valid()); // Just so we don't get an unused variable warning.
|
||||||
}
|
}
|
||||||
|
|
||||||
//add vertices to mesh
|
//add vertices to mesh
|
||||||
@@ -110,6 +111,7 @@ TEST_F(OpenMesh_Poly, cpp11_vertexrange_test) {
|
|||||||
for(PolyMesh::VertexHandle t : mesh_.vertices())
|
for(PolyMesh::VertexHandle t : mesh_.vertices())
|
||||||
{
|
{
|
||||||
FAIL() << "The Vertexrange for an empty Mesh is not empty";
|
FAIL() << "The Vertexrange for an empty Mesh is not empty";
|
||||||
|
EXPECT_TRUE(t.is_valid()); // Just so we don't get an unused variable warning.
|
||||||
}
|
}
|
||||||
|
|
||||||
//add vertices to mesh
|
//add vertices to mesh
|
||||||
@@ -140,6 +142,7 @@ TEST_F(OpenMesh_Triangle, cpp11_vvrange_test) {
|
|||||||
for(Mesh::VertexHandle t : mesh_.vv_range(vhandle[0]))
|
for(Mesh::VertexHandle t : mesh_.vv_range(vhandle[0]))
|
||||||
{
|
{
|
||||||
FAIL() << "The vvrange for a single vertex in a TriMesh is not empty";
|
FAIL() << "The vvrange for a single vertex in a TriMesh is not empty";
|
||||||
|
EXPECT_TRUE(t.is_valid()); // Just so we don't get an unused variable warning.
|
||||||
}
|
}
|
||||||
|
|
||||||
//add more vertices
|
//add more vertices
|
||||||
@@ -198,6 +201,7 @@ TEST_F(OpenMesh_Poly, cpp11_vvrange_test) {
|
|||||||
for(PolyMesh::VertexHandle t : mesh_.vv_range(vhandle[0]))
|
for(PolyMesh::VertexHandle t : mesh_.vv_range(vhandle[0]))
|
||||||
{
|
{
|
||||||
FAIL() << "The vvrange for a single vertex in a PolyMesh is not empty";
|
FAIL() << "The vvrange for a single vertex in a PolyMesh is not empty";
|
||||||
|
EXPECT_TRUE(t.is_valid()); // Just so we don't get an unused variable warning.
|
||||||
}
|
}
|
||||||
|
|
||||||
//add more vertices
|
//add more vertices
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ TEST_F(OpenMeshOthers, CalcDihedralAngre ) {
|
|||||||
|
|
||||||
double difference = fabs( 1.36944 - mesh_.calc_dihedral_angle(eh) );
|
double difference = fabs( 1.36944 - mesh_.calc_dihedral_angle(eh) );
|
||||||
|
|
||||||
EXPECT_TRUE( (difference < 0.00001 ) ) << "Wrong Dihedral angle, Difference is to big!" << std::endl;
|
EXPECT_LT(difference, 0.00001) << "Wrong Dihedral angle, Difference is to big!" << std::endl;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
#include <Unittests/unittests_common.hh>
|
#include <Unittests/unittests_common.hh>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@@ -115,6 +116,8 @@ TEST_F(OpenMeshVectorTest, cpp11_constructors) {
|
|||||||
TEST_F(OpenMeshVectorTest, cpp11_htmlColorLiteral) {
|
TEST_F(OpenMeshVectorTest, cpp11_htmlColorLiteral) {
|
||||||
static constexpr OpenMesh::Vec4f rose = 0xFFC7F1FF_htmlColor;
|
static constexpr OpenMesh::Vec4f rose = 0xFFC7F1FF_htmlColor;
|
||||||
|
|
||||||
|
EXPECT_EQ(0xFFC7F1FF_htmlColor, rose);
|
||||||
|
|
||||||
const OpenMesh::Vec4f light_blue = 0x1FCFFFFF_htmlColor;
|
const OpenMesh::Vec4f light_blue = 0x1FCFFFFF_htmlColor;
|
||||||
EXPECT_LE((OpenMesh::Vec4f(0.1215686274f, 0.8117647058f, 1.0f, 1.0f)
|
EXPECT_LE((OpenMesh::Vec4f(0.1215686274f, 0.8117647058f, 1.0f, 1.0f)
|
||||||
- light_blue).sqrnorm(), 1e-10);
|
- light_blue).sqrnorm(), 1e-10);
|
||||||
@@ -125,6 +128,199 @@ TEST_F(OpenMeshVectorTest, cpp11_htmlColorLiteral) {
|
|||||||
::value, "Bad type deduced from _htmlColor literal.");
|
::value, "Bad type deduced from _htmlColor literal.");
|
||||||
EXPECT_EQ(light_blue, light_blue_2);
|
EXPECT_EQ(light_blue, light_blue_2);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
class C {
|
||||||
|
public:
|
||||||
|
C() {}
|
||||||
|
C(const C &rhs) { ADD_FAILURE() << "Copy constructor used."; }
|
||||||
|
C(C &&rhs) { ++copy_con; }
|
||||||
|
C &operator= (const C &rhs) {
|
||||||
|
ADD_FAILURE() << "Copy assignemnt used.";
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
C &operator= (C &&rhs) { ++copy_ass; return *this; }
|
||||||
|
|
||||||
|
static int copy_con;
|
||||||
|
static int copy_ass;
|
||||||
|
};
|
||||||
|
|
||||||
|
int C::copy_con = 0;
|
||||||
|
int C::copy_ass = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks two things:
|
||||||
|
* 1) Whether VectorT works with a non-arithmetic type.
|
||||||
|
* 2) Whether move construction and assignment works.
|
||||||
|
*/
|
||||||
|
TEST_F(OpenMeshVectorTest, move_constructor_assignment) {
|
||||||
|
|
||||||
|
C::copy_con = 0;
|
||||||
|
C::copy_ass = 0;
|
||||||
|
|
||||||
|
// Test move assigning.
|
||||||
|
OpenMesh::VectorT<C, 3> x, y;
|
||||||
|
x = std::move(y);
|
||||||
|
EXPECT_EQ(3, C::copy_ass);
|
||||||
|
EXPECT_EQ(0, C::copy_con);
|
||||||
|
|
||||||
|
// Test move constructing.
|
||||||
|
OpenMesh::VectorT<C, 3> z(std::move(x));
|
||||||
|
EXPECT_EQ(3, C::copy_ass);
|
||||||
|
EXPECT_EQ(3, C::copy_con);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OpenMeshVectorTest, iterator_init) {
|
||||||
|
std::list<float> a;
|
||||||
|
a.push_back(1.0);
|
||||||
|
a.push_back(2.0);
|
||||||
|
a.push_back(3.0);
|
||||||
|
OpenMesh::Vec3f v(a.begin());
|
||||||
|
EXPECT_EQ(OpenMesh::Vec3f(1.0, 2.0, 3.0), v);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // C++11
|
||||||
|
|
||||||
|
|
||||||
|
TEST_F(OpenMeshVectorTest, BasicArithmeticInPlace) {
|
||||||
|
OpenMesh::Vec3d v1(1, 2, 3);
|
||||||
|
double s1 = 2;
|
||||||
|
const double epsilon = 1e-6;
|
||||||
|
|
||||||
|
OpenMesh::Vec3d v2add (3, 4, 6); v2add += v1;
|
||||||
|
OpenMesh::Vec3d v2sub (3, 4, 6); v2sub -= v1;
|
||||||
|
OpenMesh::Vec3d v2cmul(3, 4, 6); v2cmul *= v1;
|
||||||
|
OpenMesh::Vec3d v2cdiv(3, 4, 6); v2cdiv /= v1;
|
||||||
|
OpenMesh::Vec3d v2smul(3, 4, 6); v2smul *= s1;
|
||||||
|
OpenMesh::Vec3d v2sdiv(3, 4, 6); v2sdiv /= s1;
|
||||||
|
|
||||||
|
EXPECT_NEAR(4, v2add[0], epsilon);
|
||||||
|
EXPECT_NEAR(6, v2add[1], epsilon);
|
||||||
|
EXPECT_NEAR(9, v2add[2], epsilon);
|
||||||
|
|
||||||
|
EXPECT_NEAR(2, v2sub[0], epsilon);
|
||||||
|
EXPECT_NEAR(2, v2sub[1], epsilon);
|
||||||
|
EXPECT_NEAR(3, v2sub[2], epsilon);
|
||||||
|
|
||||||
|
EXPECT_NEAR( 3, v2cmul[0], epsilon);
|
||||||
|
EXPECT_NEAR( 8, v2cmul[1], epsilon);
|
||||||
|
EXPECT_NEAR(18, v2cmul[2], epsilon);
|
||||||
|
|
||||||
|
EXPECT_NEAR(3, v2cdiv[0], epsilon);
|
||||||
|
EXPECT_NEAR(2, v2cdiv[1], epsilon);
|
||||||
|
EXPECT_NEAR(2, v2cdiv[2], epsilon);
|
||||||
|
|
||||||
|
EXPECT_NEAR( 6, v2smul[0], epsilon);
|
||||||
|
EXPECT_NEAR( 8, v2smul[1], epsilon);
|
||||||
|
EXPECT_NEAR(12, v2smul[2], epsilon);
|
||||||
|
|
||||||
|
EXPECT_NEAR(1.5, v2sdiv[0], epsilon);
|
||||||
|
EXPECT_NEAR(2.0, v2sdiv[1], epsilon);
|
||||||
|
EXPECT_NEAR(3.0, v2sdiv[2], epsilon);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OpenMeshVectorTest, BasicArithmeticImmutable) {
|
||||||
|
OpenMesh::Vec3d v1(1, 2, 3);
|
||||||
|
const double epsilon = 1e-6;
|
||||||
|
|
||||||
|
OpenMesh::Vec3d v2add = v1 + OpenMesh::Vec3d(2, 4, 6);
|
||||||
|
OpenMesh::Vec3d v2sub = v1 - OpenMesh::Vec3d(2, 4, 6);
|
||||||
|
OpenMesh::Vec3d v2cmul = v1 * OpenMesh::Vec3d(2, 4, 6);
|
||||||
|
OpenMesh::Vec3d v2cdiv = v1 / OpenMesh::Vec3d(2, 4, 6);
|
||||||
|
OpenMesh::Vec3d v2smul = v1 * 2.0;
|
||||||
|
OpenMesh::Vec3d v2sdiv = v1 / 2.0;
|
||||||
|
OpenMesh::Vec3d v2neg = -v1;
|
||||||
|
|
||||||
|
EXPECT_NEAR(3, v2add[0], epsilon);
|
||||||
|
EXPECT_NEAR(6, v2add[1], epsilon);
|
||||||
|
EXPECT_NEAR(9, v2add[2], epsilon);
|
||||||
|
|
||||||
|
EXPECT_NEAR(-1, v2sub[0], epsilon);
|
||||||
|
EXPECT_NEAR(-2, v2sub[1], epsilon);
|
||||||
|
EXPECT_NEAR(-3, v2sub[2], epsilon);
|
||||||
|
|
||||||
|
EXPECT_NEAR( 2, v2cmul[0], epsilon);
|
||||||
|
EXPECT_NEAR( 8, v2cmul[1], epsilon);
|
||||||
|
EXPECT_NEAR(18, v2cmul[2], epsilon);
|
||||||
|
|
||||||
|
EXPECT_NEAR(0.5, v2cdiv[0], epsilon);
|
||||||
|
EXPECT_NEAR(0.5, v2cdiv[1], epsilon);
|
||||||
|
EXPECT_NEAR(0.5, v2cdiv[2], epsilon);
|
||||||
|
|
||||||
|
EXPECT_NEAR(2, v2smul[0], epsilon);
|
||||||
|
EXPECT_NEAR(4, v2smul[1], epsilon);
|
||||||
|
EXPECT_NEAR(6, v2smul[2], epsilon);
|
||||||
|
|
||||||
|
EXPECT_NEAR(0.5, v2sdiv[0], epsilon);
|
||||||
|
EXPECT_NEAR(1.0, v2sdiv[1], epsilon);
|
||||||
|
EXPECT_NEAR(1.5, v2sdiv[2], epsilon);
|
||||||
|
|
||||||
|
EXPECT_NEAR(-1, v2neg[0], epsilon);
|
||||||
|
EXPECT_NEAR(-2, v2neg[1], epsilon);
|
||||||
|
EXPECT_NEAR(-3, v2neg[2], epsilon);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OpenMeshVectorTest, BasicLinearAlgebra) {
|
||||||
|
OpenMesh::Vec3d v(1, 2, 3);
|
||||||
|
EXPECT_EQ(v[0], 1.0);
|
||||||
|
EXPECT_EQ(v[1], 2.0);
|
||||||
|
EXPECT_EQ(v[2], 3.0);
|
||||||
|
|
||||||
|
EXPECT_EQ(OpenMesh::Vec3d(-1, -2, -3), -v);
|
||||||
|
EXPECT_EQ(3, OpenMesh::Vec3d(1, 3, 2).max());
|
||||||
|
EXPECT_EQ(3, OpenMesh::Vec3d(1, 2, 3).max());
|
||||||
|
EXPECT_EQ(3, OpenMesh::Vec3d(1, 3, -4).max());
|
||||||
|
EXPECT_EQ(3, OpenMesh::Vec3d(-4, 2, 3).max());
|
||||||
|
EXPECT_EQ(4, OpenMesh::Vec3d(1, 3, -4).max_abs());
|
||||||
|
EXPECT_EQ(4, OpenMesh::Vec3d(-4, 2, 3).max_abs());
|
||||||
|
|
||||||
|
EXPECT_EQ(1, OpenMesh::Vec3d(1, 3, 2).min());
|
||||||
|
EXPECT_EQ(1, OpenMesh::Vec3d(1, 2, 3).min());
|
||||||
|
EXPECT_EQ(-4, OpenMesh::Vec3d(1, 3, -4).min());
|
||||||
|
EXPECT_EQ(-4, OpenMesh::Vec3d(-4, 2, 3).min());
|
||||||
|
EXPECT_EQ(1, OpenMesh::Vec3d(1, 3, -4).min_abs());
|
||||||
|
EXPECT_EQ(2, OpenMesh::Vec3d(-4, 2, 3).min_abs());
|
||||||
|
|
||||||
|
EXPECT_NEAR(14, OpenMesh::Vec3d(1, 2, 3) | OpenMesh::Vec3d(1, 2, 3), 1e-6);
|
||||||
|
EXPECT_NEAR(-14, OpenMesh::Vec3d(1, 2, 3) | OpenMesh::Vec3d(-1, -2, -3), 1e-6);
|
||||||
|
EXPECT_NEAR(14, OpenMesh::Vec3d(-1, -2, -3) | OpenMesh::Vec3d(-1, -2, -3), 1e-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OpenMeshVectorTest, array_init) {
|
||||||
|
float a[3]; a[0] = 1.0; a[1] = 2.0; a[2] = 3.0;
|
||||||
|
OpenMesh::Vec3f v(a);
|
||||||
|
EXPECT_EQ(OpenMesh::Vec3f(1.0, 2.0, 3.0), v);
|
||||||
|
|
||||||
|
// This should not invoke the array constructor.
|
||||||
|
OpenMesh::Vec3d v2(3.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OpenMeshVectorTest, normalized_cond) {
|
||||||
|
OpenMesh::Vec3d v1(1, -2, 3), v2(0, 0, 0);
|
||||||
|
EXPECT_EQ(OpenMesh::Vec3d(0, 0, 0), v2.normalize_cond());
|
||||||
|
const OpenMesh::Vec3d r1 =
|
||||||
|
OpenMesh::Vec3d(
|
||||||
|
0.2672612419124244,
|
||||||
|
-0.5345224838248488,
|
||||||
|
0.8017837257372732) - v1.normalize_cond();
|
||||||
|
EXPECT_NEAR(r1[0], 0.0, 1e-12);
|
||||||
|
EXPECT_NEAR(r1[1], 0.0, 1e-12);
|
||||||
|
EXPECT_NEAR(r1[2], 0.0, 1e-12);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OpenMeshVectorTest, size_dim) {
|
||||||
|
OpenMesh::Vec3d v3d(1, 2, 3);
|
||||||
|
OpenMesh::Vec3f v3f(1, 2, 3);
|
||||||
|
OpenMesh::Vec2i v2i(1, 2);
|
||||||
|
|
||||||
|
EXPECT_EQ(3u, v3d.size());
|
||||||
|
EXPECT_EQ(3, v3d.dim());
|
||||||
|
EXPECT_EQ(3u, v3f.size());
|
||||||
|
EXPECT_EQ(3, v3f.dim());
|
||||||
|
EXPECT_EQ(2u, v2i.size());
|
||||||
|
EXPECT_EQ(2, v2i.dim());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user