1 /******************************************************************************
2
3 This source file is part of the Avogadro project.
4
5 Copyright 2008-2009 Marcus D. Hanwell
6 Copyright 2010-2013 Kitware, Inc.
7
8 This source code is released under the New BSD License, (the "License").
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15
16 ******************************************************************************/
17
18 #include "cube.h"
19
20 #include "molecule.h"
21 #include "mutex.h"
22
23 namespace Avogadro {
24 namespace Core {
25
Cube()26 Cube::Cube()
27 : m_data(0), m_min(0.0, 0.0, 0.0), m_max(0.0, 0.0, 0.0),
28 m_spacing(0.0, 0.0, 0.0), m_points(0, 0, 0), m_minValue(0.0),
29 m_maxValue(0.0), m_lock(new Mutex)
30 {
31 }
32
~Cube()33 Cube::~Cube()
34 {
35 delete m_lock;
36 m_lock = 0;
37 }
38
setLimits(const Vector3 & min_,const Vector3 & max_,const Vector3i & points)39 bool Cube::setLimits(const Vector3& min_, const Vector3& max_,
40 const Vector3i& points)
41 {
42 // We can calculate all necessary properties and initialise our data
43 Vector3 delta = max_ - min_;
44 m_spacing =
45 Vector3(delta.x() / (points.x() - 1), delta.y() / (points.y() - 1),
46 delta.z() / (points.z() - 1));
47 m_min = min_;
48 m_max = max_;
49 m_points = points;
50 m_data.resize(m_points.x() * m_points.y() * m_points.z());
51 return true;
52 }
53
setLimits(const Vector3 & min_,const Vector3 & max_,double spacing_)54 bool Cube::setLimits(const Vector3& min_, const Vector3& max_, double spacing_)
55 {
56 Vector3 delta = max_ - min_;
57 delta = delta / spacing_;
58 return setLimits(min_, max_, delta.cast<int>());
59 }
60
setLimits(const Vector3 & min_,const Vector3i & dim,double spacing_)61 bool Cube::setLimits(const Vector3& min_, const Vector3i& dim, double spacing_)
62 {
63 return setLimits(min_, dim, Vector3(spacing_, spacing_, spacing_));
64 }
65
setLimits(const Vector3 & min_,const Vector3i & dim,const Vector3 & spacing_)66 bool Cube::setLimits(const Vector3& min_, const Vector3i& dim,
67 const Vector3& spacing_)
68 {
69 Vector3 max_ = Vector3(min_.x() + (dim.x() - 1) * spacing_[0],
70 min_.y() + (dim.y() - 1) * spacing_[1],
71 min_.z() + (dim.z() - 1) * spacing_[2]);
72 m_min = min_;
73 m_max = max_;
74 m_points = dim;
75 m_spacing = spacing_;
76 m_data.resize(m_points.x() * m_points.y() * m_points.z());
77 return true;
78 }
79
setLimits(const Cube & cube)80 bool Cube::setLimits(const Cube& cube)
81 {
82 m_min = cube.m_min;
83 m_max = cube.m_max;
84 m_points = cube.m_points;
85 m_spacing = cube.m_spacing;
86 m_data.resize(m_points.x() * m_points.y() * m_points.z());
87 return true;
88 }
89
setLimits(const Molecule & mol,double spacing_,double padding)90 bool Cube::setLimits(const Molecule& mol, double spacing_, double padding)
91 {
92 Index numAtoms = mol.atomCount();
93 Vector3 min_, max_;
94 if (numAtoms) {
95 Vector3 curPos = min_ = max_ = mol.atomPositions3d()[0];
96 for (Index i = 1; i < numAtoms; ++i) {
97 curPos = mol.atomPositions3d()[i];
98 if (curPos.x() < min_.x())
99 min_.x() = curPos.x();
100 if (curPos.x() > max_.x())
101 max_.x() = curPos.x();
102 if (curPos.y() < min_.y())
103 min_.y() = curPos.y();
104 if (curPos.y() > max_.y())
105 max_.y() = curPos.y();
106 if (curPos.z() < min_.z())
107 min_.z() = curPos.z();
108 if (curPos.z() > max_.z())
109 max_.z() = curPos.z();
110 }
111 } else {
112 min_ = max_ = Vector3::Zero();
113 }
114
115 // Now to take care of the padding term
116 min_ += Vector3(-padding, -padding, -padding);
117 max_ += Vector3(padding, padding, padding);
118
119 return setLimits(min_, max_, spacing_);
120 }
121
data()122 std::vector<double>* Cube::data()
123 {
124 return &m_data;
125 }
126
data() const127 const std::vector<double>* Cube::data() const
128 {
129 return &m_data;
130 }
131
setData(const std::vector<double> & values)132 bool Cube::setData(const std::vector<double>& values)
133 {
134 if (!values.size())
135 return false;
136
137 if (static_cast<int>(values.size()) ==
138 m_points.x() * m_points.y() * m_points.z()) {
139 m_data = values;
140 // Now to update the minimum and maximum values
141 m_minValue = m_maxValue = m_data[0];
142 for (std::vector<double>::const_iterator it = values.begin();
143 it != values.end(); ++it) {
144 if (*it < m_minValue)
145 m_minValue = *it;
146 else if (*it > m_maxValue)
147 m_maxValue = *it;
148 }
149 return true;
150 } else {
151 return false;
152 }
153 }
154
addData(const std::vector<double> & values)155 bool Cube::addData(const std::vector<double>& values)
156 {
157 // Initialise the cube to zero if necessary
158 if (!m_data.size())
159 m_data.resize(m_points.x() * m_points.y() * m_points.z());
160 if (values.size() != m_data.size() || !values.size())
161 return false;
162 for (unsigned int i = 0; i < m_data.size(); i++) {
163 m_data[i] += values[i];
164 if (m_data[i] < m_minValue)
165 m_minValue = m_data[i];
166 else if (m_data[i] > m_maxValue)
167 m_maxValue = m_data[i];
168 }
169 return true;
170 }
171
closestIndex(const Vector3 & pos) const172 unsigned int Cube::closestIndex(const Vector3& pos) const
173 {
174 int i, j, k;
175 // Calculate how many steps each coordinate is along its axis
176 i = int((pos.x() - m_min.x()) / m_spacing.x());
177 j = int((pos.y() - m_min.y()) / m_spacing.y());
178 k = int((pos.z() - m_min.z()) / m_spacing.z());
179 return i * m_points.y() * m_points.z() + j * m_points.z() + k;
180 }
181
indexVector(const Vector3 & pos) const182 Vector3i Cube::indexVector(const Vector3& pos) const
183 {
184 // Calculate how many steps each coordinate is along its axis
185 int i, j, k;
186 i = int((pos.x() - m_min.x()) / m_spacing.x());
187 j = int((pos.y() - m_min.y()) / m_spacing.y());
188 k = int((pos.z() - m_min.z()) / m_spacing.z());
189 return Vector3i(i, j, k);
190 }
191
position(unsigned int index) const192 Vector3 Cube::position(unsigned int index) const
193 {
194 int x, y, z;
195 x = int(index / (m_points.y() * m_points.z()));
196 y = int((index - (x * m_points.y() * m_points.z())) / m_points.z());
197 z = index % m_points.z();
198 return Vector3(x * m_spacing.x() + m_min.x(), y * m_spacing.y() + m_min.y(),
199 z * m_spacing.z() + m_min.z());
200 }
201
value(int i,int j,int k) const202 double Cube::value(int i, int j, int k) const
203 {
204 unsigned int index = i * m_points.y() * m_points.z() + j * m_points.z() + k;
205 if (index < m_data.size())
206 return m_data[index];
207 else
208 return 0.0;
209 }
210
value(const Vector3i & pos) const211 double Cube::value(const Vector3i& pos) const
212 {
213 unsigned int index =
214 pos.x() * m_points.y() * m_points.z() + pos.y() * m_points.z() + pos.z();
215 if (index < m_data.size())
216 return m_data[index];
217 else
218 return 6969.0;
219 }
220
valuef(const Vector3f & pos) const221 float Cube::valuef(const Vector3f& pos) const
222 {
223 // This is a really expensive operation and so should be avoided
224 // Interpolate the value at the supplied vector - trilinear interpolation...
225 Vector3f delta = pos - m_min.cast<float>();
226 // Find the integer low and high corners
227 Vector3i lC(static_cast<int>(delta.x() / m_spacing.x()),
228 static_cast<int>(delta.y() / m_spacing.y()),
229 static_cast<int>(delta.z() / m_spacing.z()));
230 Vector3i hC(lC.x() + 1, lC.y() + 1, lC.z() + 1);
231 // So there are six corners in total - work out the delta of the position
232 // and the low corner
233 const Vector3f lCf(lC.cast<float>());
234 const Vector3f spacingf(m_spacing.cast<float>());
235 Vector3f P((delta.x() - lCf.x() * spacingf.x()) / spacingf.x(),
236 (delta.y() - lCf.y() * spacingf.y()) / spacingf.y(),
237 (delta.z() - lCf.z() * spacingf.z()) / spacingf.z());
238 Vector3f dP = Vector3f(1.0f, 1.0f, 1.0f) - P;
239 // Now calculate and return the interpolated value
240 return static_cast<float>(
241 value(lC.x(), lC.y(), lC.z()) * dP.x() * dP.y() * dP.z() +
242 value(hC.x(), lC.y(), lC.z()) * P.x() * dP.y() * dP.z() +
243 value(lC.x(), hC.y(), lC.z()) * dP.x() * P.y() * dP.z() +
244 value(lC.x(), lC.y(), hC.z()) * dP.x() * dP.y() * P.z() +
245 value(hC.x(), lC.y(), hC.z()) * P.x() * dP.y() * P.z() +
246 value(lC.x(), hC.y(), hC.z()) * dP.x() * P.y() * P.z() +
247 value(hC.x(), hC.y(), lC.z()) * P.x() * P.y() * dP.z() +
248 value(hC.x(), hC.y(), hC.z()) * P.x() * P.y() * P.z());
249 }
250
value(const Vector3 & pos) const251 double Cube::value(const Vector3& pos) const
252 {
253 // This is a really expensive operation and so should be avoided
254 // Interpolate the value at the supplied vector - trilinear interpolation...
255 Vector3 delta = pos - m_min;
256 // Find the integer low and high corners
257 Vector3i lC(static_cast<int>(delta.x() / m_spacing.x()),
258 static_cast<int>(delta.y() / m_spacing.y()),
259 static_cast<int>(delta.z() / m_spacing.z()));
260 Vector3i hC(lC.x() + 1, lC.y() + 1, lC.z() + 1);
261 // So there are six corners in total - work out the delta of the position
262 // and the low corner
263 Vector3 P((delta.x() - lC.x() * m_spacing.x()) / m_spacing.x(),
264 (delta.y() - lC.y() * m_spacing.y()) / m_spacing.y(),
265 (delta.z() - lC.z() * m_spacing.z()) / m_spacing.z());
266 Vector3 dP = Vector3(1.0, 1.0, 1.0) - P;
267 // Now calculate and return the interpolated value
268 return value(lC.x(), lC.y(), lC.z()) * dP.x() * dP.y() * dP.z() +
269 value(hC.x(), lC.y(), lC.z()) * P.x() * dP.y() * dP.z() +
270 value(lC.x(), hC.y(), lC.z()) * dP.x() * P.y() * dP.z() +
271 value(lC.x(), lC.y(), hC.z()) * dP.x() * dP.y() * P.z() +
272 value(hC.x(), lC.y(), hC.z()) * P.x() * dP.y() * P.z() +
273 value(lC.x(), hC.y(), hC.z()) * dP.x() * P.y() * P.z() +
274 value(hC.x(), hC.y(), lC.z()) * P.x() * P.y() * dP.z() +
275 value(hC.x(), hC.y(), hC.z()) * P.x() * P.y() * P.z();
276 }
277
setValue(int i,int j,int k,double value_)278 bool Cube::setValue(int i, int j, int k, double value_)
279 {
280 unsigned int index = i * m_points.y() * m_points.z() + j * m_points.z() + k;
281 if (index < m_data.size()) {
282 m_data[index] = value_;
283 if (value_ < m_minValue)
284 m_minValue = value_;
285 else if (value_ > m_maxValue)
286 m_maxValue = value_;
287 return true;
288 } else {
289 return false;
290 }
291 }
292
293 } // End Core namespace
294 } // End Avogadro namespace
295