pytessel 1.2.4__cp39-cp39-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pytessel might be problematic. Click here for more details.
- pytessel/__init__.py +3 -0
- pytessel/_version.py +1 -0
- pytessel/isosurface.cpp +561 -0
- pytessel/isosurface.h +180 -0
- pytessel/isosurface_mesh.cpp +144 -0
- pytessel/isosurface_mesh.h +104 -0
- pytessel/pytessel.cpython-39-darwin.so +0 -0
- pytessel/scalar_field.cpp +239 -0
- pytessel/scalar_field.h +104 -0
- pytessel-1.2.4.dist-info/LICENSE +674 -0
- pytessel-1.2.4.dist-info/METADATA +169 -0
- pytessel-1.2.4.dist-info/RECORD +14 -0
- pytessel-1.2.4.dist-info/WHEEL +5 -0
- pytessel-1.2.4.dist-info/top_level.txt +1 -0
pytessel/isosurface.h
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**************************************************************************
|
|
2
|
+
* *
|
|
3
|
+
* Author: Ivo Filot <ivo@ivofilot.nl> *
|
|
4
|
+
* *
|
|
5
|
+
* PyTessel is free software: *
|
|
6
|
+
* you can redistribute it and/or modify it under the terms of the *
|
|
7
|
+
* GNU General Public License as published by the Free Software *
|
|
8
|
+
* Foundation, either version 3 of the License, or (at your option) *
|
|
9
|
+
* any later version. *
|
|
10
|
+
* *
|
|
11
|
+
* PyTessel is distributed in the hope that it will be useful, *
|
|
12
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty *
|
|
13
|
+
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
14
|
+
* See the GNU General Public License for more details. *
|
|
15
|
+
* *
|
|
16
|
+
* You should have received a copy of the GNU General Public License *
|
|
17
|
+
* along with this program. If not, see http://www.gnu.org/licenses/. *
|
|
18
|
+
* *
|
|
19
|
+
**************************************************************************/
|
|
20
|
+
|
|
21
|
+
#pragma once
|
|
22
|
+
|
|
23
|
+
#include <vector>
|
|
24
|
+
#include <iostream>
|
|
25
|
+
#include <cmath>
|
|
26
|
+
#include <mutex>
|
|
27
|
+
#include <memory>
|
|
28
|
+
|
|
29
|
+
#include "edgetable.h"
|
|
30
|
+
#include "triangletable.h"
|
|
31
|
+
#include "scalar_field.h"
|
|
32
|
+
|
|
33
|
+
#define PRECISION_LIMIT 0.000000001
|
|
34
|
+
|
|
35
|
+
/*
|
|
36
|
+
* z
|
|
37
|
+
* |
|
|
38
|
+
* 4----5
|
|
39
|
+
* /| /|
|
|
40
|
+
* 7-|--6 |
|
|
41
|
+
* | 0--|-1--- y
|
|
42
|
+
* |/ |/
|
|
43
|
+
* 3----2
|
|
44
|
+
* /
|
|
45
|
+
* x
|
|
46
|
+
*
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
class Cube{
|
|
50
|
+
private:
|
|
51
|
+
unsigned int i,j,k; // starting position of the cube
|
|
52
|
+
float values[8]; // vector holding cube values
|
|
53
|
+
unsigned int cubidx; // cubeindex (whether there is an intersection)
|
|
54
|
+
|
|
55
|
+
public:
|
|
56
|
+
Cube();
|
|
57
|
+
|
|
58
|
+
Cube(unsigned int _i, unsigned int _j, unsigned int _k, const ScalarField &_vp);
|
|
59
|
+
|
|
60
|
+
void set_cube_index(float _isovalue);
|
|
61
|
+
|
|
62
|
+
unsigned int get_cube_index() const;
|
|
63
|
+
|
|
64
|
+
float get_value_from_vertex(unsigned int _p) const;
|
|
65
|
+
Vec3 get_position_from_vertex(unsigned int _p) const;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/*
|
|
69
|
+
* + 0
|
|
70
|
+
* /|\
|
|
71
|
+
* / | \
|
|
72
|
+
* / | \
|
|
73
|
+
* / | \
|
|
74
|
+
* / | \
|
|
75
|
+
* / | \
|
|
76
|
+
* +-------------+ 1
|
|
77
|
+
* 3 \ | /
|
|
78
|
+
* \ | /
|
|
79
|
+
* \ | /
|
|
80
|
+
* \ | /
|
|
81
|
+
* \ | /
|
|
82
|
+
* \|/
|
|
83
|
+
* + 2
|
|
84
|
+
*/
|
|
85
|
+
|
|
86
|
+
class Tetrahedron{
|
|
87
|
+
private:
|
|
88
|
+
unsigned int i,j,k; //!< starting position of the cube
|
|
89
|
+
float values[4];
|
|
90
|
+
unsigned int tetidx; //!< cubeindex (whether there is an intersection)
|
|
91
|
+
Vec3 pos[4]; //!< coordinates of the gridpoints
|
|
92
|
+
|
|
93
|
+
public:
|
|
94
|
+
Tetrahedron(unsigned int _i, unsigned int _j, unsigned int _k, const ScalarField &_vp, unsigned int _pos);
|
|
95
|
+
|
|
96
|
+
void set_tetrahedron_index(float _isovalue);
|
|
97
|
+
|
|
98
|
+
unsigned int get_tetrahedron_index() const;
|
|
99
|
+
|
|
100
|
+
float get_value_from_vertex(unsigned int _p) const;
|
|
101
|
+
|
|
102
|
+
const Vec3& get_position_from_vertex(unsigned int _p) const;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
class Triangle{
|
|
106
|
+
public:
|
|
107
|
+
Vec3 p1, p2, p3;
|
|
108
|
+
|
|
109
|
+
Triangle();
|
|
110
|
+
|
|
111
|
+
Triangle(const Vec3 &_p1, const Vec3 &_p2, const Vec3 &_p3);
|
|
112
|
+
|
|
113
|
+
void transform_to_real(const ScalarField &_vp);
|
|
114
|
+
|
|
115
|
+
float get_x(unsigned int i) const;
|
|
116
|
+
|
|
117
|
+
float get_y(unsigned int i) const;
|
|
118
|
+
|
|
119
|
+
float get_z(unsigned int i) const;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @brief generates an isosurface using either the marching cubes or the
|
|
124
|
+
* marching tetrahedra algorithm, input is a (tabulated) scalar
|
|
125
|
+
* field
|
|
126
|
+
*/
|
|
127
|
+
class IsoSurface {
|
|
128
|
+
private:
|
|
129
|
+
std::vector<Cube> cube_table;
|
|
130
|
+
std::vector<Tetrahedron> tetrahedra_table;
|
|
131
|
+
std::vector<Triangle> triangles;
|
|
132
|
+
std::shared_ptr<ScalarField> vp_ptr; // pointer to ScalarField obj
|
|
133
|
+
unsigned int grid_dimensions[3];
|
|
134
|
+
float isovalue; // isovalue setting
|
|
135
|
+
|
|
136
|
+
public:
|
|
137
|
+
/**
|
|
138
|
+
* @brief default constructor
|
|
139
|
+
*
|
|
140
|
+
* @param _sf pointer to ScalarField object
|
|
141
|
+
*/
|
|
142
|
+
IsoSurface(const std::shared_ptr<ScalarField>& _sf);
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* @brief generate isosurface using marching cubes algorithm
|
|
146
|
+
*
|
|
147
|
+
* @param[in] _isovalue The isovalue
|
|
148
|
+
*/
|
|
149
|
+
void marching_cubes(float _isovalue);
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* @brief generate isosurface using marching tetrahedra algorithm
|
|
153
|
+
*
|
|
154
|
+
* @param[in] _isovalue The isovalue
|
|
155
|
+
*/
|
|
156
|
+
void marching_tetrahedra(float _isovalue);
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* @brief Gets the triangles pointer.
|
|
160
|
+
*
|
|
161
|
+
* @return The triangles pointer.
|
|
162
|
+
*/
|
|
163
|
+
const std::vector<Triangle>* get_triangles_ptr() const;
|
|
164
|
+
|
|
165
|
+
inline float get_isovalue() const {
|
|
166
|
+
return this->isovalue;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
inline const std::shared_ptr<ScalarField>& get_scalar_field() const {
|
|
170
|
+
return this->vp_ptr;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
private:
|
|
174
|
+
void sample_grid_with_cubes(float _isovalue);
|
|
175
|
+
void sample_grid_with_tetrahedra(float _isovalue);
|
|
176
|
+
void construct_triangles_from_cubes(float _isovalue);
|
|
177
|
+
void construct_triangles_from_tetrahedra(float _isovalue);
|
|
178
|
+
Vec3 interpolate_from_cubes(const Cube &_cub, unsigned int _p1, unsigned int _p2, float _isovalue);
|
|
179
|
+
Vec3 interpolate_from_tetrahedra(const Tetrahedron &_cub, unsigned int _p1, unsigned int _p2, float _isovalue);
|
|
180
|
+
};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**************************************************************************
|
|
2
|
+
* *
|
|
3
|
+
* Author: Ivo Filot <ivo@ivofilot.nl> *
|
|
4
|
+
* *
|
|
5
|
+
* PyTessel is free software: *
|
|
6
|
+
* you can redistribute it and/or modify it under the terms of the *
|
|
7
|
+
* GNU General Public License as published by the Free Software *
|
|
8
|
+
* Foundation, either version 3 of the License, or (at your option) *
|
|
9
|
+
* any later version. *
|
|
10
|
+
* *
|
|
11
|
+
* PyTessel is distributed in the hope that it will be useful, *
|
|
12
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty *
|
|
13
|
+
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
14
|
+
* See the GNU General Public License for more details. *
|
|
15
|
+
* *
|
|
16
|
+
* You should have received a copy of the GNU General Public License *
|
|
17
|
+
* along with this program. If not, see http://www.gnu.org/licenses/. *
|
|
18
|
+
* *
|
|
19
|
+
**************************************************************************/
|
|
20
|
+
|
|
21
|
+
#include "isosurface_mesh.h"
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @brief build isosurface mesh object
|
|
25
|
+
*
|
|
26
|
+
* @param[in] _sf pointer to scalar field
|
|
27
|
+
* @param[in] _is pointer to isosurface
|
|
28
|
+
*/
|
|
29
|
+
IsoSurfaceMesh::IsoSurfaceMesh(const std::shared_ptr<const ScalarField>& _sf,
|
|
30
|
+
const std::shared_ptr<const IsoSurface>& _is) :
|
|
31
|
+
sf(_sf),
|
|
32
|
+
is(_is) {
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @brief construct surface mesh
|
|
37
|
+
*
|
|
38
|
+
* @param[in] center whether to center structure
|
|
39
|
+
*/
|
|
40
|
+
void IsoSurfaceMesh::construct_mesh(bool center_mesh) {
|
|
41
|
+
// grab center
|
|
42
|
+
this->center = this->sf->get_mat_unitcell() * Vec3(0.5, 0.5, 0.5);
|
|
43
|
+
|
|
44
|
+
for(unsigned int i=0; i<this->is->get_triangles_ptr()->size(); i++) {
|
|
45
|
+
// load all index vertices in a map; this operation needs to be done, else a SEGFAULT
|
|
46
|
+
// will be thrown further down the lines
|
|
47
|
+
this->get_index_vertex(is->get_triangles_ptr()->at(i).p1);
|
|
48
|
+
this->get_index_vertex(is->get_triangles_ptr()->at(i).p2);
|
|
49
|
+
this->get_index_vertex(is->get_triangles_ptr()->at(i).p3);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// build vertex vector from unordered map
|
|
53
|
+
this->vertices.resize(this->vertices_map.size());
|
|
54
|
+
for(auto it : this->vertices_map) {
|
|
55
|
+
this->vertices[it.second] = it.first;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
double dev = 0.01;
|
|
59
|
+
this->normals.resize(this->vertices.size());
|
|
60
|
+
|
|
61
|
+
// calculate normal vectors
|
|
62
|
+
#pragma omp parallel for schedule(static)
|
|
63
|
+
for(unsigned int i=0; i<this->vertices.size(); i++) {
|
|
64
|
+
// get derivatives
|
|
65
|
+
double dx0 = sf->get_value_interp(this->vertices[i].x - dev, this->vertices[i].y, this->vertices[i].z);
|
|
66
|
+
double dx1 = sf->get_value_interp(this->vertices[i].x + dev, this->vertices[i].y, this->vertices[i].z);
|
|
67
|
+
|
|
68
|
+
double dy0 = sf->get_value_interp(this->vertices[i].x, this->vertices[i].y - dev, this->vertices[i].z);
|
|
69
|
+
double dy1 = sf->get_value_interp(this->vertices[i].x, this->vertices[i].y + dev, this->vertices[i].z);
|
|
70
|
+
|
|
71
|
+
double dz0 = sf->get_value_interp(this->vertices[i].x, this->vertices[i].y, this->vertices[i].z - dev);
|
|
72
|
+
double dz1 = sf->get_value_interp(this->vertices[i].x, this->vertices[i].y, this->vertices[i].z + dev);
|
|
73
|
+
|
|
74
|
+
Vec3 normal((dx1 - dx0) / (2.0 * dev),
|
|
75
|
+
(dy1 - dy0) / (2.0 * dev),
|
|
76
|
+
(dz1 - dz0) / (2.0 * dev));
|
|
77
|
+
normal = -1 * normal.normalized(); // the negative of the gradient is the correct normal
|
|
78
|
+
|
|
79
|
+
this->normals[i] = normal * sgn(sf->get_value_interp(this->vertices[i].x, this->vertices[i].y, this->vertices[i].z));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// build indices in right orientation based on face normal
|
|
83
|
+
for(unsigned int i=0; i<this->is->get_triangles_ptr()->size(); i++) {
|
|
84
|
+
// calculate face normal
|
|
85
|
+
unsigned int id1 = this->get_index_vertex(is->get_triangles_ptr()->at(i).p1);
|
|
86
|
+
unsigned int id2 = this->get_index_vertex(is->get_triangles_ptr()->at(i).p2);
|
|
87
|
+
unsigned int id3 = this->get_index_vertex(is->get_triangles_ptr()->at(i).p3);
|
|
88
|
+
|
|
89
|
+
// calculate the orientation of the face with respect to the normal
|
|
90
|
+
const Vec3 face_normal = (this->normals[id1] + this->normals[id2] + this->normals[id3]) / 3.0f;
|
|
91
|
+
const Vec3 orientation_face = ((this->vertices[id2] - this->vertices[id1]).cross(this->vertices[id3] - this->vertices[id1])).normalized();
|
|
92
|
+
const float orientation = face_normal.dot(orientation_face);
|
|
93
|
+
|
|
94
|
+
// if orientation is positive, the orientation is correct, if it is negative, the orientation is incorrect and two indices should be swapped
|
|
95
|
+
if(orientation > 0.0f) {
|
|
96
|
+
this->indices.push_back(id1);
|
|
97
|
+
this->indices.push_back(id2);
|
|
98
|
+
this->indices.push_back(id3);
|
|
99
|
+
} else {
|
|
100
|
+
this->indices.push_back(id2);
|
|
101
|
+
this->indices.push_back(id1);
|
|
102
|
+
this->indices.push_back(id3);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// center structure
|
|
107
|
+
if(center_mesh) {
|
|
108
|
+
Vec3 sum = this->sf->get_mat_unitcell() * Vec3(0.5f, 0.5f, 0.5f);
|
|
109
|
+
|
|
110
|
+
#pragma omp parallel for
|
|
111
|
+
for(unsigned int i=0; i<this->vertices.size(); i++) {
|
|
112
|
+
this->vertices[i] -= sum;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @brief get the index of a vertex from unordered map
|
|
119
|
+
*
|
|
120
|
+
* @param[in] v vertex coordinates
|
|
121
|
+
*
|
|
122
|
+
* @return the index
|
|
123
|
+
*/
|
|
124
|
+
unsigned int IsoSurfaceMesh::get_index_vertex(const Vec3 v) {
|
|
125
|
+
auto got = this->vertices_map.find(v);
|
|
126
|
+
if(got != this->vertices_map.end()) {
|
|
127
|
+
return got->second;
|
|
128
|
+
} else {
|
|
129
|
+
this->vertices_map.emplace(v, this->vertices_map.size());
|
|
130
|
+
return this->get_index_vertex(v);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
std::vector<float> IsoSurfaceMesh::get_vertices() const {
|
|
135
|
+
return std::vector<float>(&this->vertices[0].x, &this->vertices[0].x + this->vertices.size() * 3);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
std::vector<float> IsoSurfaceMesh::get_normals() const {
|
|
139
|
+
return std::vector<float>(&this->normals[0].x, &this->normals[0].x + this->normals.size() * 3);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const std::vector<unsigned int>& IsoSurfaceMesh::get_indices() const {
|
|
143
|
+
return this->indices;
|
|
144
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**************************************************************************
|
|
2
|
+
* *
|
|
3
|
+
* Author: Ivo Filot <ivo@ivofilot.nl> *
|
|
4
|
+
* *
|
|
5
|
+
* PyTessel is free software: *
|
|
6
|
+
* you can redistribute it and/or modify it under the terms of the *
|
|
7
|
+
* GNU General Public License as published by the Free Software *
|
|
8
|
+
* Foundation, either version 3 of the License, or (at your option) *
|
|
9
|
+
* any later version. *
|
|
10
|
+
* *
|
|
11
|
+
* PyTessel is distributed in the hope that it will be useful, *
|
|
12
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty *
|
|
13
|
+
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
14
|
+
* See the GNU General Public License for more details. *
|
|
15
|
+
* *
|
|
16
|
+
* You should have received a copy of the GNU General Public License *
|
|
17
|
+
* along with this program. If not, see http://www.gnu.org/licenses/. *
|
|
18
|
+
* *
|
|
19
|
+
**************************************************************************/
|
|
20
|
+
|
|
21
|
+
#pragma once
|
|
22
|
+
|
|
23
|
+
#include <fstream>
|
|
24
|
+
#include <set>
|
|
25
|
+
#include <vector>
|
|
26
|
+
#include <unordered_map>
|
|
27
|
+
#include <memory>
|
|
28
|
+
|
|
29
|
+
#include "vec3.h"
|
|
30
|
+
#include "isosurface.h"
|
|
31
|
+
|
|
32
|
+
// add SGN function for Windows
|
|
33
|
+
template <typename T> float sgn(T val) {
|
|
34
|
+
return (T(0) < val) - (val < T(0));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @brief structure to put Vec3f in a map
|
|
39
|
+
*/
|
|
40
|
+
struct KeyFuncs
|
|
41
|
+
{
|
|
42
|
+
size_t operator()(const Vec3& k)const
|
|
43
|
+
{
|
|
44
|
+
return std::hash<float>()(k.x) ^ std::hash<float>()(k.y) ^ std::hash<float>()(k.z);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
bool operator()(const Vec3& a, const Vec3& b)const
|
|
48
|
+
{
|
|
49
|
+
return a.x == b.x && a.y == b.y && a.z == b.z;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @brief Class for iso surface mesh.
|
|
55
|
+
*/
|
|
56
|
+
class IsoSurfaceMesh{
|
|
57
|
+
private:
|
|
58
|
+
std::unordered_map<Vec3, unsigned int, KeyFuncs, KeyFuncs> vertices_map;
|
|
59
|
+
std::vector<Vec3> vertices;
|
|
60
|
+
std::vector<Vec3> normals;
|
|
61
|
+
std::vector<unsigned int> indices;
|
|
62
|
+
|
|
63
|
+
std::shared_ptr<const ScalarField> sf;
|
|
64
|
+
std::shared_ptr<const IsoSurface> is;
|
|
65
|
+
|
|
66
|
+
Vec3 center;
|
|
67
|
+
|
|
68
|
+
public:
|
|
69
|
+
/**
|
|
70
|
+
* @brief build isosurface mesh object
|
|
71
|
+
*
|
|
72
|
+
* @param[in] _sf pointer to scalar field
|
|
73
|
+
* @param[in] _is pointer to isosurface
|
|
74
|
+
*/
|
|
75
|
+
IsoSurfaceMesh(const std::shared_ptr<const ScalarField>& _sf,
|
|
76
|
+
const std::shared_ptr<const IsoSurface>& _is);
|
|
77
|
+
|
|
78
|
+
IsoSurfaceMesh(const std::vector<float>& vertices,
|
|
79
|
+
const std::vector<float>& normals,
|
|
80
|
+
const std::vector<unsigned int>& indices);
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @brief construct surface mesh
|
|
84
|
+
*
|
|
85
|
+
* @param[in] center_mesh whether to center structure
|
|
86
|
+
*/
|
|
87
|
+
void construct_mesh(bool center_mesh);
|
|
88
|
+
|
|
89
|
+
std::vector<float> get_vertices() const;
|
|
90
|
+
|
|
91
|
+
std::vector<float> get_normals() const;
|
|
92
|
+
|
|
93
|
+
const std::vector<unsigned int>& get_indices() const;
|
|
94
|
+
|
|
95
|
+
private:
|
|
96
|
+
/**
|
|
97
|
+
* @brief get the index of a vertex from unordered map
|
|
98
|
+
*
|
|
99
|
+
* @param[in] v vertex coordinates
|
|
100
|
+
*
|
|
101
|
+
* @return the index
|
|
102
|
+
*/
|
|
103
|
+
unsigned int get_index_vertex(const Vec3 v);
|
|
104
|
+
};
|
|
Binary file
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**************************************************************************
|
|
2
|
+
* *
|
|
3
|
+
* Author: Ivo Filot <ivo@ivofilot.nl> *
|
|
4
|
+
* *
|
|
5
|
+
* PyTessel is free software: *
|
|
6
|
+
* you can redistribute it and/or modify it under the terms of the *
|
|
7
|
+
* GNU General Public License as published by the Free Software *
|
|
8
|
+
* Foundation, either version 3 of the License, or (at your option) *
|
|
9
|
+
* any later version. *
|
|
10
|
+
* *
|
|
11
|
+
* PyTessel is distributed in the hope that it will be useful, *
|
|
12
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty *
|
|
13
|
+
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
14
|
+
* See the GNU General Public License for more details. *
|
|
15
|
+
* *
|
|
16
|
+
* You should have received a copy of the GNU General Public License *
|
|
17
|
+
* along with this program. If not, see http://www.gnu.org/licenses/. *
|
|
18
|
+
* *
|
|
19
|
+
**************************************************************************/
|
|
20
|
+
|
|
21
|
+
#include "scalar_field.h"
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @brief constructor
|
|
25
|
+
*
|
|
26
|
+
* @param[in] _filename url to filename
|
|
27
|
+
* @param[in] _flag_is_locpot whether this file is a locpot
|
|
28
|
+
*/
|
|
29
|
+
ScalarField::ScalarField(const std::vector<float>& _grid,
|
|
30
|
+
const std::vector<unsigned int>& _dimensions,
|
|
31
|
+
const std::vector<float>& _unitcell) {
|
|
32
|
+
|
|
33
|
+
this->grid = _grid;
|
|
34
|
+
this->grid_dimensions = {_dimensions[0], _dimensions[1], _dimensions[2]};
|
|
35
|
+
for(unsigned int i=0; i<3; i++) {
|
|
36
|
+
for(unsigned int j=0; j<3; j++) {
|
|
37
|
+
this->unitcell[i][j] = _unitcell[i*3 + j];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
this->inverse(this->unitcell, &this->unitcell_inverse);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/*
|
|
44
|
+
* float get_value_interp(x,y,z)
|
|
45
|
+
*
|
|
46
|
+
* Grabs a value from the 3D scalar field. Calculate the value
|
|
47
|
+
* by using a trilinear interpolation.
|
|
48
|
+
*
|
|
49
|
+
* The trilinear interpolation algorithm has been extracted from:
|
|
50
|
+
* http://paulbourke.net/miscellaneous/interpolation/
|
|
51
|
+
*
|
|
52
|
+
* Future algorithm can make use of a cubic interpolation.
|
|
53
|
+
*
|
|
54
|
+
*/
|
|
55
|
+
float ScalarField::get_value_interp(float x, float y, float z) const {
|
|
56
|
+
if(!this->is_inside(x,y,z)) {
|
|
57
|
+
return 0.0f;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// cast the input to the nearest grid point
|
|
61
|
+
Vec3 r = this->realspace_to_grid(x,y,z);
|
|
62
|
+
|
|
63
|
+
// recast
|
|
64
|
+
if(r.x < 0.0) r.x += (float)this->grid_dimensions[0];
|
|
65
|
+
if(r.y < 0.0) r.y += (float)this->grid_dimensions[1];
|
|
66
|
+
if(r.z < 0.0) r.z += (float)this->grid_dimensions[2];
|
|
67
|
+
|
|
68
|
+
// calculate value using trilinear interpolation
|
|
69
|
+
float xd = remainderf(r.x, 1.0);
|
|
70
|
+
float yd = remainderf(r.y, 1.0);
|
|
71
|
+
float zd = remainderf(r.z, 1.0);
|
|
72
|
+
|
|
73
|
+
if(xd < 0) xd += 1.0;
|
|
74
|
+
if(yd < 0) yd += 1.0;
|
|
75
|
+
if(zd < 0) zd += 1.0;
|
|
76
|
+
|
|
77
|
+
float x0 = fmod(floor(r.x), this->grid_dimensions[0]);
|
|
78
|
+
float x1 = fmod(ceil(r.x), this->grid_dimensions[0]);
|
|
79
|
+
float y0 = fmod(floor(r.y), this->grid_dimensions[1]);
|
|
80
|
+
float y1 = fmod(ceil(r.y), this->grid_dimensions[1]);
|
|
81
|
+
float z0 = fmod(floor(r.z), this->grid_dimensions[2]);
|
|
82
|
+
float z1 = fmod(ceil(r.z), this->grid_dimensions[2]);
|
|
83
|
+
|
|
84
|
+
return
|
|
85
|
+
this->get_value(x0, y0, z0) * (1.0 - xd) * (1.0 - yd) * (1.0 - zd) +
|
|
86
|
+
this->get_value(x1, y0, z0) * xd * (1.0 - yd) * (1.0 - zd) +
|
|
87
|
+
this->get_value(x0, y1, z0) * (1.0 - xd) * yd * (1.0 - zd) +
|
|
88
|
+
this->get_value(x0, y0, z1) * (1.0 - xd) * (1.0 - yd) * zd +
|
|
89
|
+
this->get_value(x1, y0, z1) * xd * (1.0 - yd) * zd +
|
|
90
|
+
this->get_value(x0, y1, z1) * (1.0 - xd) * yd * zd +
|
|
91
|
+
this->get_value(x1, y1, z0) * xd * yd * (1.0 - zd) +
|
|
92
|
+
this->get_value(x1, y1, z1) * xd * yd * zd;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @brief test whether point is inside unit cell
|
|
97
|
+
*
|
|
98
|
+
* @param[in] x x position
|
|
99
|
+
* @param[in] y y position
|
|
100
|
+
* @param[in] z z position
|
|
101
|
+
*
|
|
102
|
+
* @return True if inside, False otherwise.
|
|
103
|
+
*/
|
|
104
|
+
bool ScalarField::is_inside(float x, float y, float z) const {
|
|
105
|
+
// cast the input to the nearest grid point
|
|
106
|
+
Vec3 d = this->realspace_to_direct(x,y,z);
|
|
107
|
+
|
|
108
|
+
if(d.x < 0 || d.x > 1.0) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
if(d.y < 0 || d.y > 1.0) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
if(d.z < 0 || d.z > 1.0) {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/*
|
|
122
|
+
* float get_value(i,j,k)
|
|
123
|
+
*
|
|
124
|
+
* Grabs the value at a particular grid point.
|
|
125
|
+
*
|
|
126
|
+
* This is a convenience function for the get_value_interp() function
|
|
127
|
+
*
|
|
128
|
+
*/
|
|
129
|
+
float ScalarField::get_value(unsigned int i, unsigned int j, unsigned int k) const {
|
|
130
|
+
unsigned int idx = k * this->grid_dimensions[0] * this->grid_dimensions[1] +
|
|
131
|
+
j * this->grid_dimensions[0] +
|
|
132
|
+
i;
|
|
133
|
+
return this->grid[idx];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/*
|
|
137
|
+
* Vec3 grid_to_realspace(i,j,k)
|
|
138
|
+
*
|
|
139
|
+
* Converts a grid point to a realspace vector. This function
|
|
140
|
+
* is not being used at the moment.
|
|
141
|
+
*
|
|
142
|
+
*/
|
|
143
|
+
Vec3 ScalarField::grid_to_realspace(float i, float j, float k) const {
|
|
144
|
+
float dx = (float)i / (float)grid_dimensions[0];
|
|
145
|
+
float dy = (float)j / (float)grid_dimensions[1];
|
|
146
|
+
float dz = (float)k / (float)grid_dimensions[2];
|
|
147
|
+
|
|
148
|
+
Vec3 r;
|
|
149
|
+
r.x = this->unitcell[0][0] * dx + this->unitcell[1][0] * dy + this->unitcell[2][0] * dz;
|
|
150
|
+
r.y = this->unitcell[0][1] * dx + this->unitcell[1][1] * dy + this->unitcell[2][1] * dz;
|
|
151
|
+
r.z = this->unitcell[0][2] * dx + this->unitcell[1][2] * dy + this->unitcell[2][2] * dz;
|
|
152
|
+
|
|
153
|
+
return r;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
Vec3 ScalarField::realspace_to_direct(float x, float y, float z) const {
|
|
157
|
+
Vec3 d;
|
|
158
|
+
d.x = this->unitcell_inverse[0][0] * x + this->unitcell_inverse[0][1] * y + this->unitcell_inverse[0][2] * z;
|
|
159
|
+
d.y = this->unitcell_inverse[1][0] * x + this->unitcell_inverse[1][1] * y + this->unitcell_inverse[1][2] * z;
|
|
160
|
+
d.z = this->unitcell_inverse[2][0] * x + this->unitcell_inverse[2][1] * y + this->unitcell_inverse[2][2] * z;
|
|
161
|
+
|
|
162
|
+
return d;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/*
|
|
166
|
+
* Vec3 realspace_to_grid(i,j,k)
|
|
167
|
+
*
|
|
168
|
+
* Convert 3d realspace vector to a position on the grid. Non-integer
|
|
169
|
+
* values (i.e. floating point) are given as the result.
|
|
170
|
+
*
|
|
171
|
+
* This is a convenience function for the get_value_interp() function
|
|
172
|
+
*
|
|
173
|
+
*/
|
|
174
|
+
Vec3 ScalarField::realspace_to_grid(float i, float j, float k) const {
|
|
175
|
+
Vec3 g = this->realspace_to_direct(i, j, k);
|
|
176
|
+
|
|
177
|
+
g.x *= float(this->grid_dimensions[0]);
|
|
178
|
+
g.y *= float(this->grid_dimensions[1]);
|
|
179
|
+
g.z *= float(this->grid_dimensions[2]);
|
|
180
|
+
|
|
181
|
+
return g;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
void ScalarField::copy_grid_dimensions(unsigned int _grid_dimensions[]) const {
|
|
185
|
+
for(unsigned int i=0; i<3; i++) {
|
|
186
|
+
_grid_dimensions[i] = this->grid_dimensions[i];
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
float ScalarField::get_max() const {
|
|
191
|
+
return *std::max_element(this->grid.begin(), this->grid.end());
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
float ScalarField::get_min() const {
|
|
195
|
+
return *std::min_element(this->grid.begin(), this->grid.end());
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
void ScalarField::inverse(const mat33& mat, mat33* invmat) {
|
|
199
|
+
// computes the inverse of a matrix m
|
|
200
|
+
float det = mat[0][0] * (mat[1][1] * mat[2][2] - mat[2][1] * mat[1][2]) -
|
|
201
|
+
mat[0][1] * (mat[1][0] * mat[2][2] - mat[1][2] * mat[2][0]) +
|
|
202
|
+
mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]);
|
|
203
|
+
|
|
204
|
+
float invdet = 1.0 / det;
|
|
205
|
+
|
|
206
|
+
(*invmat)[0][0] = (mat[1][1] * mat[2][2] - mat[2][1] * mat[1][2]) * invdet;
|
|
207
|
+
(*invmat)[0][1] = (mat[0][2] * mat[2][1] - mat[0][1] * mat[2][2]) * invdet;
|
|
208
|
+
(*invmat)[0][2] = (mat[0][1] * mat[1][2] - mat[0][2] * mat[1][1]) * invdet;
|
|
209
|
+
(*invmat)[1][0] = (mat[1][2] * mat[2][0] - mat[1][0] * mat[2][2]) * invdet;
|
|
210
|
+
(*invmat)[1][1] = (mat[0][0] * mat[2][2] - mat[0][2] * mat[2][0]) * invdet;
|
|
211
|
+
(*invmat)[1][2] = (mat[1][0] * mat[0][2] - mat[0][0] * mat[1][2]) * invdet;
|
|
212
|
+
(*invmat)[2][0] = (mat[1][0] * mat[2][1] - mat[2][0] * mat[1][1]) * invdet;
|
|
213
|
+
(*invmat)[2][1] = (mat[2][0] * mat[0][1] - mat[0][0] * mat[2][1]) * invdet;
|
|
214
|
+
(*invmat)[2][2] = (mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1]) * invdet;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
std::vector<float> ScalarField::get_unitcell_vf() const {
|
|
218
|
+
std::vector<float> ans(9,0.0);
|
|
219
|
+
|
|
220
|
+
for(unsigned int i=0; i<3; i++) {
|
|
221
|
+
for(unsigned int j=0; j<3; j++) {
|
|
222
|
+
ans[i*3 + j] = this->unitcell[i][j];
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return ans;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
std::vector<float> ScalarField::get_unitcell_inverse() const {
|
|
230
|
+
std::vector<float> ans(9,0.0);
|
|
231
|
+
|
|
232
|
+
for(unsigned int i=0; i<3; i++) {
|
|
233
|
+
for(unsigned int j=0; j<3; j++) {
|
|
234
|
+
ans[i*3 + j] = this->unitcell_inverse[i][j];
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return ans;
|
|
239
|
+
}
|