10#include "MantidNexus/NexusFile.h"
12#include <boost/version.hpp>
15#if BOOST_VERSION < 106700
16#include <boost/math/common_factor.hpp>
17using boost::math::gcd;
19#include <boost/integer/common_factor.hpp>
20using boost::integer::gcd;
31double nearInt(
double val,
double eps,
double mult)
noexcept {
36 if (std::abs(val - std::round(val)) > eps) {
37 mult *= std::ceil(val / eps) * eps / val;
56void V3D::spherical(
const double R,
const double theta,
const double phi)
noexcept {
57 constexpr double deg2rad = M_PI / 180.0;
70 m_pt[2] = R * cos(polar);
71 const double ct = R * sin(polar);
72 m_pt[0] = ct * cos(azimuth);
73 m_pt[1] = ct * sin(azimuth);
95 m_pt[1] = R * cos(polar);
96 const double ct = R * sin(polar);
97 m_pt[0] = ct * cos(azimuth);
98 m_pt[2] = ct * sin(azimuth);
117 constexpr double rad2deg = 180.0 / M_PI;
121 theta = acos(m_pt[2] / R) *
rad2deg;
122 phi = atan2(m_pt[1], m_pt[0]) *
rad2deg;
130 const double ND(
norm());
132 throw std::runtime_error(
"Unable to normalize a zero length vector.");
140 std::transform(
m_pt.cbegin(),
m_pt.cend(),
m_pt.begin(), [](
auto p) { return std::round(p); });
148 const double R = distance(v);
150 const double zOffset = m_pt[2] - v.m_pt[2];
151 return acos(zOffset / R);
163 const double ratio = this->
cosAngle(v);
166 else if (ratio <= -1.0)
178 const double n1 =
norm();
179 const double n2 = v.
norm();
180 if (n1 == 0. || n2 == 0.) {
181 throw std::runtime_error(
"Cannot calculate an angle when one of the vectors has zero length.");
198 for (
int i = 0; i < 3; i++) {
203 const double det = T.
Invert();
204 if (std::abs(det) < 1e-13)
215 const double xold(m_pt[0]), yold(m_pt[1]), zold(m_pt[2]);
216 for (
size_t i = 0; i < m_pt.size(); ++i) {
217 m_pt[i] = A[i][0] * xold + A[i][1] * yold + A[i][2] * zold;
228 const V3D &Av = *
this;
229 const V3D Tmp((Bv - Av).cross_prod(Cv - Av));
239 return std::none_of(m_pt.cbegin(), m_pt.cend(), [&
tolerance](
const auto p) { return std::abs(p) > tolerance; });
244 const auto l = norm();
258 double max = m_pt[0] * m_pt[0];
260 double u2 = m_pt[1] * m_pt[1];
261 int idx = (m_pt[0] > 0) ? 1 : -1;
264 idx = (m_pt[1] > 0) ? 2 : -2;
267 u2 = m_pt[2] * m_pt[2];
270 idx = (m_pt[2] > 0) ? 3 : -3;
291 if (vectors.size() != 2)
292 throw std::invalid_argument(
"makeVectorsOrthogonal() only works with 2 vectors");
297 std::vector<V3D> out;
299 out.emplace_back(v0);
307 out.emplace_back(v1);
311 out.emplace_back(v2);
328 OX << m_pt[0] <<
" " << m_pt[1] <<
" " << m_pt[2];
333 std::ostringstream mess;
341 std::istringstream mess(str);
358 std::getline(IX, in);
359 size_t i = in.find_first_of(
'[');
360 if (i == std::string::npos)
361 throw std::runtime_error(
"Wrong format for V3D input: " + in);
362 size_t j = in.find_last_of(
']');
363 if (j == std::string::npos || j < i + 6)
364 throw std::runtime_error(
"Wrong format for V3D input: " + in);
366 size_t c1 = in.find_first_of(
',');
367 size_t c2 = in.find_first_of(
',', c1 + 1);
368 if (c1 == std::string::npos || c2 == std::string::npos)
369 throw std::runtime_error(
"Wrong format for V3D input: [" + in +
"]");
371 m_pt[0] = std::stod(in.substr(i + 1, c1 - i - 1));
372 m_pt[1] = std::stod(in.substr(c1 + 1, c2 - c1 - 1));
373 m_pt[2] = std::stod(in.substr(c2 + 1, j - c2 - 1));
406 file->putData(
m_pt.data());
416 std::vector<double> data;
417 file->readData(
name, data);
418 if (data.size() != 3)
419 throw std::runtime_error(
"Unexpected data size when reading a V3D NXS field '" +
name +
"'. Expected 3.");
420 std::copy(data.cbegin(), data.cend(),
m_pt.begin());
426 if (eps < FLT_EPSILON)
431 double ax = std::abs(
m_pt[0]);
432 double ay = std::abs(
m_pt[1]);
433 double az = std::abs(
m_pt[2]);
435 double amax = (ax > ay) ? ax : ay;
436 amax = (az > amax) ? az : amax;
437 if (amax < FLT_EPSILON)
438 throw(std::invalid_argument(
"vector length is less then accuracy requested"));
454 mult = nearInt(ax, eps, mult);
455 mult = nearInt(ay, eps, mult);
456 mult = nearInt(az, eps, mult);
458 const size_t iax = std::lround(ax * mult / eps);
459 const size_t iay = std::lround(ay * mult / eps);
460 const size_t iaz = std::lround(az * mult / eps);
462 const size_t div = gcd(iax, gcd(iay, iaz));
463 mult /= (
static_cast<double>(div) * eps);
476 const double mag_sq_1 = v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2];
477 const double mag_sq_2 = v2[0] * v2[0] + v2[1] * v2[1] + v2[2] * v2[2];
478 return (mag_sq_1 < mag_sq_2);
488 const double conversionFactor = inDegrees ? 180. / M_PI : 1.0;
489 const double divisor = this->
norm();
491 throw std::runtime_error(
"Cannot calculate direction angles for zero length vector");
493 return V3D(conversionFactor * acos(
m_pt[0] / divisor), conversionFactor * acos(
m_pt[1] / divisor),
494 conversionFactor * acos(
m_pt[2] / divisor));
503 if (std::abs(
static_cast<int>(
m_pt[0])) > MaxOrder)
504 MaxOrder = std::abs(
static_cast<int>(
m_pt[0]));
505 if (std::abs(
static_cast<int>(
m_pt[1])) > MaxOrder)
506 MaxOrder = std::abs(
static_cast<int>(
m_pt[1]));
507 if (std::abs(
static_cast<int>(
m_pt[2])) > MaxOrder)
508 MaxOrder = std::abs(
static_cast<int>(
m_pt[2]));
523 return std::abs(
m_pt[0] - std::round(
m_pt[0])) +
524 std::abs(
m_pt[1] - std::round(
m_pt[1])) +
525 std::abs(
m_pt[2] - std::round(
m_pt[2]));
T Invert()
LU inversion routine.
void rotate(V3D &) const
Rotate a vector.
void setRotation(const double deg)
Set the rotation (both don't change rotation axis)
void spherical_rad(const double R, const double polar, const double azimuth) noexcept
Sets the vector position based on spherical coordinates, in radians.
std::array< double, 3 > m_pt
static bool compareMagnitude(const Kernel::V3D &v1, const Kernel::V3D &v2)
Convenience method for sorting list of V3D objects based on magnitude.
bool coLinear(const V3D &, const V3D &) const noexcept
Determines if this,B,C are colinear.
static std::vector< V3D > makeVectorsOrthogonal(const std::vector< V3D > &vectors)
Take a list of 2 vectors and makes a 3D orthogonal system out of them The first vector i0 is taken as...
void azimuth_polar_SNS(const double R, const double azimuth, const double polar) noexcept
Sets the vector position based on azimuth and polar angle, in RADIANS, in the SNS instrument coordina...
V3D absoluteValue() const
Absolute value.
int maxCoeff() const
Maximum absolute integer value.
double zenith(const V3D &) const noexcept
Zenith (theta) angle between this and another vector.
void loadNexus(Nexus::File *file, const std::string &name)
Load the object from an open NeXus file.
constexpr double scalar_prod(const V3D &v) const noexcept
Calculates the cross product.
void printSelf(std::ostream &) const
Prints a text representation of itself in format "[x,y,z]".
V3D & operator*=(const V3D &v) noexcept
Self-Inner product.
V3D & operator/=(const V3D &v) noexcept
Self-Inner division.
double normalize()
Make a normalized vector (return norm value)
constexpr V3D cross_prod(const V3D &v) const noexcept
Cross product (this * argument)
std::string toString() const
V3D directionAngles(bool inDegrees=true) const
Direction angles.
void spherical(const double R, const double theta, const double phi) noexcept
Sets the vector position based on spherical coordinates.
void read(std::istream &)
Read data from a stream.
void saveNexus(Nexus::File *file, const std::string &name) const
Save the object to an open NeXus file.
double angle(const V3D &) const
Angle between this and another vector.
void rotate(const Matrix< double > &) noexcept
Rotate a point by a matrix.
double norm() const noexcept
int reBase(const V3D &, const V3D &, const V3D &) noexcept
rebase to new basis vector
void fromString(const std::string &str)
Sets the vector using a string.
bool unitVector(const double tolerance=Kernel::Tolerance) const noexcept
double hklError() const
Calculates the error in hkl.
void readPrinted(std::istream &)
Read data from a stream in the format returned by printSelf ("[x,y,z]").
void write(std::ostream &) const
Write out the point values.
void getSpherical(double &R, double &theta, double &phi) const noexcept
Return the vector's position in spherical coordinates.
double toMillerIndexes(double eps=1.e-3)
transform vector into form, used to describe directions in crystallogaphical coodinate system
double cosAngle(const V3D &) const
cos(Angle) between this and another vector
void round() noexcept
Round each component to the nearest integer.
int masterDir(const double Tol=1e-3) const noexcept
Determine if there is a master direction.
bool nullVector(const double tolerance=1e-3) const noexcept
Determine if the point is null.
static unsigned short constexpr FLOAT64
constexpr double deg2rad
Defines units/enum for Crystal work.
MANTID_KERNEL_DLL std::ostream & operator<<(std::ostream &, CPUTimer &)
Convenience function to provide for easier debug printing.
MANTID_KERNEL_DLL std::istream & operator>>(std::istream &, Interpolation &)
Reads in parameter value.
constexpr double Tolerance
Standard tolerance value.
MANTID_KERNEL_DLL V3D normalize(V3D v)
Normalizes a V3D.