/*************************************************************************** * Copyright (C) gempa GmbH * * All rights reserved. * * Contact: gempa GmbH (seiscomp-dev@gempa.de) * * * * GNU Affero General Public License Usage * * This file may be used under the terms of the GNU Affero * * Public License version 3.0 as published by the Free Software Foundation * * and appearing in the file LICENSE included in the packaging of this * * file. Please review the following information to ensure the GNU Affero * * Public License version 3.0 requirements will be met: * * https://www.gnu.org/licenses/agpl-3.0.html. * * * * Other Usage * * Alternatively, this file may be used in accordance with the terms and * * conditions contained in a signed written agreement between you and * * gempa GmbH. * ***************************************************************************/ template void vec2angle(const Math::Vector3 &v, T &strike, T &dip) { if ( fabs(v.x) < 0.0001 && fabs(v.y) < 0.0001 ) { strike = 0; dip = 0; } else { // TODO: Is this correct? if ( v.z < 0 ) { strike = (T)(atan2(-v.y,-v.x)); dip = (T)(acos(-v.z)); } else { strike = (T)(atan2(v.y,v.x)); dip = (T)(acos(v.z)); } if ( strike < 0 ) strike += (2*M_PI); strike = rad2deg(strike); } dip = rad2deg(HALF_PI-dip); } template void angle2vec(T strike, T dip, Math::Vector3 &v) { T rdip = deg2rad(dip); T rstrike = deg2rad(strike); v.x = cos(rdip)*cos(rstrike); v.y = cos(rdip)*sin(rstrike); v.z = sin(rdip); } template bool pa2nd(const Math::Vector3 &t, const Math::Vector3 &p, Math::Vector3 &n, Math::Vector3 &d) { n = t + p; n.normalize(); d = t - p; d.normalize(); if ( n.z > 0 ) { n *= -1; d *= -1; } return true; } template bool nd2pa(const Math::Vector3 &n, const Math::Vector3 &d, Math::Vector3 &t, Math::Vector3 &p) { p = n - d; p.normalize(); if ( p.z < 0 ) p *= -1; t = n + d; t.normalize(); if ( t.z < 0 ) t *= -1; return true; } template bool nd2tensor(const Math::Vector3 &n, const Math::Vector3 &d, Math::Tensor2S &t) { t._11 = 2*d.x*n.x; t._12 = d.x*n.y+d.y*n.x; t._13 = d.x*n.z+d.z*n.x; t._22 = 2*d.y*n.y; t._23 = d.y*n.z+d.z*n.y; t._33 = 2*d.z*n.z; return true; } template bool np2tensor(const NODAL_PLANE &np, Math::Tensor2S &t) { Math::Vector3 n, d; np2nd(np, n, d); nd2tensor(n, d, t); return true; } template bool nd2np(const Math::Vector3 &n, const Math::Vector3 &d, NODAL_PLANE &np) { if ( fabs(n.z) == 1 ) { np.dip = 0; np.str = 0; np.rake = atan2(-d.y,d.x); } else { np.dip = acos(-n.z); np.str = atan2(-n.x, n.y); np.rake = atan2(-d.z/sin(np.dip),d.x*cos(np.str)+d.y*sin(np.str)); } np.str = (double)fmod(np.str+(2*M_PI),(2*M_PI)); return true; } template bool np2nd(const NODAL_PLANE &np, Math::Vector3 &n, Math::Vector3 &d) { T rdip = deg2rad(np.dip), rstr = deg2rad(np.str), rrake = deg2rad(np.rake); n.x = -sin(rdip)*sin(rstr); n.y = sin(rdip)*cos(rstr); n.z = -cos(rdip); d.x = cos(rrake)*cos(rstr)+cos(rdip)*sin(rrake)*sin(rstr); d.y = cos(rrake)*sin(rstr)-cos(rdip)*sin(rrake)*cos(rstr); d.z = -sin(rdip) *sin(rrake); return true; } template bool nd2dc(const Math::Vector3 &n, const Math::Vector3 &d, NODAL_PLANE *NP1, NODAL_PLANE *NP2) { // Compute DC from normal and slip vector nd2np(n, d, *NP1); Math::Vector3 n1(d); Math::Vector3 d1(n); // Rotate n-d system be 180 degree if ( n1.z > 0 ) { n1 *= -1; d1 *= -1; } // Compute DC from normal (rotated slip) and slip (rotated normal) vector nd2np(n1, d1, *NP2); // Convert both nodal planes from radiant to degree np2deg(*NP1); np2deg(*NP2); return true; } template void rtp2tensor(T mrr, T mtt, T mpp, T mrt, T mrp, T mtp, Math::Tensor2S &tensor) { tensor._33 = mrr; tensor._11 = mtt; tensor._22 = mpp; tensor._13 = mrt; tensor._23 = -mrp; tensor._12 = -mtp; } template double spectral2clvd(const Math::Spectral2S &spec) { double mean = (spec.a1 + spec.a2 + spec.a3) / 3; double v[3] = {fabs(spec.a1-mean), fabs(spec.a2-mean), fabs(spec.a3-mean)}; std::sort(v, v+3); double eps = v[0] / v[2]; return 200.0*eps; } template void spectral2axis(const Math::Spectral2S &spec, AXIS &t, AXIS &n, AXIS &p, int expo) { t.val = spec.a1; t.expo = expo; n.val = spec.a2; n.expo = expo; p.val = spec.a3; p.expo = expo; vec2angle(spec.n1, t.str, t.dip); vec2angle(spec.n2, n.str, n.dip); vec2angle(spec.n3, p.str, p.dip); } template void axis2spectral(const AXIS &t, const AXIS &n, const AXIS &p, int expo, Math::Spectral2S &spec) { angle2vec(t.str, t.dip, spec.n1); angle2vec(n.str, n.dip, spec.n2); angle2vec(p.str, p.dip, spec.n3); spec.a1 = t.val * pow((T)10, (T)t.expo-expo); spec.a2 = n.val * pow((T)10, (T)n.expo-expo); spec.a3 = p.val * pow((T)10, (T)p.expo-expo); } template void axis2tensor(const AXIS &t, const AXIS &n, const AXIS &p, int expo, Math::Tensor2S &tensor) { Math::Spectral2S spec; axis2spectral(t, n, p, expo, spec); spec.compose(tensor); } template void spectral2matrix(const Math::Spectral2S &spec, Math::Matrix3 &m) { Math::Vector3 x3, x1, x2; // Convert principle axis to tensor orientation pa2nd(spec.n1, spec.n3, x3, x1); // Calculate null axis x2.cross(x3, x1); // Slip axis m.setColumn(0, Math::Vector3(x1.x,x1.y,x1.z)); // Dip axis m.setColumn(1, Math::Vector3(x2.x,x2.y,x2.z)); // Fault normal m.setColumn(2, Math::Vector3(x3.x,x3.y,x3.z)); } template bool tensor2matrix(const Math::Tensor2S &t, Math::Matrix3 &m) { Math::Spectral2S spec; if ( !spec.spect(t) ) return false; spec.sort(); spectral2matrix(spec, m); return true; }