From 8c590e4449c71990b7ca29defd277386707155ac Mon Sep 17 00:00:00 2001 From: Don Cross Date: Sun, 15 Dec 2019 20:23:35 -0500 Subject: [PATCH] Python: implemented InverseRotation function. Cleaned up trailing whitespace. Also added missing check in Python apsis test where I did not verify that each apsis kind was correct. --- generate/astro_check.js | 5 +++-- generate/elong_test.js | 2 +- generate/eol_hack.js | 8 ++++---- generate/jpl_horizons_check.js | 4 ++-- generate/lunar_apsis_test.js | 2 +- generate/moon_phase_test.js | 4 ++-- generate/rise_set_test.js | 4 ++-- generate/seasons_test.js | 4 ++-- generate/template/astronomy.py | 22 ++++++++++++++++++++++ generate/test.py | 28 +++++++++++++++++++++++++++- generate/trimspace.js | 4 ++-- source/python/README.md | 17 +++++++++++++++++ source/python/astronomy.py | 26 ++++++++++++++++++++++++-- 13 files changed, 109 insertions(+), 21 deletions(-) diff --git a/generate/astro_check.js b/generate/astro_check.js index 67a35b37..09ca687f 100644 --- a/generate/astro_check.js +++ b/generate/astro_check.js @@ -1,3 +1,4 @@ +'use strict'; var Astronomy = require('../source/js/astronomy.min.js'); var date = Astronomy.MakeTime(new Date('1700-01-01T00:00:00Z')); @@ -15,8 +16,8 @@ while (date.tt < stop.tt) { if (body !== 'Moon') { pos = Astronomy.HelioVector(body, date); console.log(`v ${body} ${pos.t.tt.toFixed(16)} ${pos.x.toFixed(16)} ${pos.y.toFixed(16)} ${pos.z.toFixed(16)}`); - - if (body !== 'Earth') { + + if (body !== 'Earth') { j2000 = Astronomy.Equator(body, date, observer, false, false); ofdate = Astronomy.Equator(body, date, observer, true, true); hor = Astronomy.Horizon(date, observer, ofdate.ra, ofdate.dec); diff --git a/generate/elong_test.js b/generate/elong_test.js index 0ad971d1..c39f1a99 100644 --- a/generate/elong_test.js +++ b/generate/elong_test.js @@ -86,7 +86,7 @@ function LoadData(filename) { const text = fs.readFileSync(filename, {encoding:'utf8'}); const lines = text.trimRight().split('\n'); let data = []; - for (let row of lines) { + for (let row of lines) { let token = row.split(/\s+/); data.push({date:new Date(token[0]), body:token[1]}); } diff --git a/generate/eol_hack.js b/generate/eol_hack.js index 3297bc64..6a1f6d2d 100644 --- a/generate/eol_hack.js +++ b/generate/eol_hack.js @@ -1,10 +1,10 @@ /* eol_hack.js - Don Cross - + Fixes line endings in a text file to be CR LF pairs. This is a hack so that there is no diff noise caused by running jsdoc2md from Windows. - + See open bug at: https://github.com/jsdoc2md/jsdoc-to-markdown/issues/112 */ @@ -14,11 +14,11 @@ const fs = require('fs'); function FixFile(filename) { const inText = fs.readFileSync(filename, 'utf8'); const outText = inText.replace(/\r?\n|\r\n?/g, '\r\n'); - + if (inText === outText) { console.log(`eol_hack.js: Leaving file as-is: ${filename}`); } else { - fs.writeFileSync(filename, outText, 'utf8'); + fs.writeFileSync(filename, outText, 'utf8'); console.log(`eol_hack.js: Rewrote line endings: ${filename}`); } } diff --git a/generate/jpl_horizons_check.js b/generate/jpl_horizons_check.js index d56232c8..a07e0b09 100644 --- a/generate/jpl_horizons_check.js +++ b/generate/jpl_horizons_check.js @@ -116,7 +116,7 @@ function ProcessRow(context, row) { const hour = parseInt(m[4]); const minute = parseInt(m[5]); const date = new Date(Date.UTC(year, month, day, hour, minute)); - + const jpl = { m_ra: ParseRightAscension(m[6]), m_dec: ParseDeclination(m[7]), @@ -203,7 +203,7 @@ function ProcessFile(inFileName) { throw `Missing refraction option in file: ${inFileName}`; } } - } else if (row === '$$EOE') { + } else if (row === '$$EOE') { return PrintSummary(context); } else { ProcessRow(context, row); diff --git a/generate/lunar_apsis_test.js b/generate/lunar_apsis_test.js index 5989b000..4565e267 100644 --- a/generate/lunar_apsis_test.js +++ b/generate/lunar_apsis_test.js @@ -56,7 +56,7 @@ function Test() { const elapsed = (time_after - time_before) / 1000; console.log(`lunar_apsis_test: verified ${count} lines, max time error = ${max_minute_error.toFixed(3)} minutes, max dist error = ${max_dist_error.toFixed(3)} km.`); - + if (count !== 2651) throw 'FATAL: Did not process the expected number of data rows!'; diff --git a/generate/moon_phase_test.js b/generate/moon_phase_test.js index f5d2abeb..41e09d6b 100644 --- a/generate/moon_phase_test.js +++ b/generate/moon_phase_test.js @@ -7,7 +7,7 @@ function LoadMoonPhaseData(filename) { const text = fs.readFileSync(filename, {encoding:'utf8'}); const lines = text.trimRight().split('\n'); let data = []; - for (let row of lines) { + for (let row of lines) { let token = row.split(' '); data.push({quarter:parseInt(token[0]), date:new Date(token[1])}); } @@ -68,7 +68,7 @@ function SearchYear(year, data, index) { ++index; ++count; mq = Astronomy.NextMoonQuarter(mq); - date = mq.time.date; + date = mq.time.date; } console.log(`SearchYear(${year}): count=${count}, maxdiff=${maxdiff.toFixed(3)}`); return 0; diff --git a/generate/rise_set_test.js b/generate/rise_set_test.js index 1d450552..5d0d6fd7 100644 --- a/generate/rise_set_test.js +++ b/generate/rise_set_test.js @@ -13,7 +13,7 @@ function LoadTestData(filename) { const lines = text.trimRight().split('\n'); let data = []; let lnum = 0; - for (let row of lines) { + for (let row of lines) { let token = row.split(/\s+/g); data.push({ lnum: ++lnum, @@ -38,7 +38,7 @@ function Test() { let body; let observer; let r_search_date, r_date; - let s_search_date, s_date; + let s_search_date, s_date; let a_date, b_date, a_dir, b_dir; let sum_minutes = 0; let max_minutes = 0; diff --git a/generate/seasons_test.js b/generate/seasons_test.js index 9f4dd71d..78cc81bf 100644 --- a/generate/seasons_test.js +++ b/generate/seasons_test.js @@ -10,10 +10,10 @@ function LoadTestData(filename) { let lnum = 0; let minByMonth = []; let maxByMonth = []; - for (let row of lines) { + for (let row of lines) { let token = row.split(/\s+/g); let item = { - lnum: ++lnum, + lnum: ++lnum, date: new Date(token[0]), name: token[1] // Perihelion, Equinox, Solstice, Aphelion }; diff --git a/generate/template/astronomy.py b/generate/template/astronomy.py index 66aaee0c..256f8a65 100644 --- a/generate/template/astronomy.py +++ b/generate/template/astronomy.py @@ -3022,6 +3022,28 @@ def NextLunarApsis(apsis): raise InternalError() return next +def InverseRotation(rotation): + """Calculates the inverse of a rotation matrix. + + Given a rotation matrix that performs some coordinate transform, + this function returns the matrix that reverses that trasnform. + + Parameters + ---------- + rotation : RotationMatrix + The rotation matrix to be inverted. + + Returns + ------- + RotationMatrix + The inverse rotation matrix. + """ + return RotationMatrix([ + [rotation.rot[0][0], rotation.rot[1][0], rotation.rot[2][0]], + [rotation.rot[0][1], rotation.rot[1][1], rotation.rot[2][1]], + [rotation.rot[0][2], rotation.rot[1][2], rotation.rot[2][2]] + ]) + def RotateVector(rotation, vector): """Applies a rotation to a vector, yielding a rotated vector. diff --git a/generate/test.py b/generate/test.py index 959b0a38..23d63408 100755 --- a/generate/test.py +++ b/generate/test.py @@ -702,7 +702,10 @@ def LunarApsis(filename): if not correct_time: print('LunarApsis({} line {}): invalid time'.format(filename, lnum)) return 1 - kind = int(tokenlist[0]) + kind = astronomy.ApsisKind(int(tokenlist[0])) + if apsis.kind != kind: + print('LunarApsis({} line {}): Expected kind {} but found {}'.format(filename, lnum, kind, apsis.kind)) + return 1 dist_km = float(tokenlist[2]) diff_minutes = (24.0 * 60.0) * abs(apsis.time.ut - correct_time.ut) diff_km = abs(apsis.dist_km - dist_km) @@ -725,7 +728,30 @@ def Test_Apsis(): #----------------------------------------------------------------------------------------------------------- +def CompareMatrices(caller, a, b, tolerance): + for i in range(3): + for j in range(3): + diff = abs(a.rot[i][j] - b.rot[i][j]) + if diff > tolerance: + print('ERROR({}): matrix[{}][{}] = {}, expected {}, diff {}'.format(caller, i, j, a.rot[i][j], b.rot[i][j], diff)) + sys.exit(1) + +def Rotation_MatrixInverse(): + a = astronomy.RotationMatrix([ + [1, 4, 7], + [2, 5, 8], + [3, 6, 9] + ]) + v = astronomy.RotationMatrix([ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9] + ]) + b = astronomy.InverseRotation(a) + CompareMatrices('Rotation_MatrixInverse', b, v, 0) + def Test_Rotation(): + Rotation_MatrixInverse() print('Python Test_Rotation: PASS') return 0 diff --git a/generate/trimspace.js b/generate/trimspace.js index d7530e77..0afcfb9e 100644 --- a/generate/trimspace.js +++ b/generate/trimspace.js @@ -12,11 +12,11 @@ const fs = require('fs'); function FixFile(filename) { const inText = fs.readFileSync(filename, 'utf8'); const outText = inText.replace(/[ \t]+(\r?\n)/g, '$1'); - + if (inText === outText) { console.log(`trimspace.js: Leaving file as-is: ${filename}`); } else { - fs.writeFileSync(filename, outText, 'utf8'); + fs.writeFileSync(filename, outText, 'utf8'); console.log(`trimspace.js: Removed trailing whitespace from file: ${filename}`); } } diff --git a/source/python/README.md b/source/python/README.md index 808eaeca..3ce1aed1 100644 --- a/source/python/README.md +++ b/source/python/README.md @@ -780,6 +780,23 @@ This will be less than or equal to zero. --- + +### InverseRotation(rotation) + +**Calculates the inverse of a rotation matrix.** + +Given a rotation matrix that performs some coordinate transform, +this function returns the matrix that reverses that trasnform. + +| Type | Parameter | Description | +| --- | --- | --- | +| [`RotationMatrix`](#RotationMatrix) | `rotation` | The rotation matrix to be inverted. | + +### Returns: RotationMatrix +The inverse rotation matrix. + +--- + ### LongitudeFromSun(body, time) diff --git a/source/python/astronomy.py b/source/python/astronomy.py index b9ec400a..2b6d0cc7 100644 --- a/source/python/astronomy.py +++ b/source/python/astronomy.py @@ -5083,6 +5083,28 @@ def NextLunarApsis(apsis): raise InternalError() return next +def InverseRotation(rotation): + """Calculates the inverse of a rotation matrix. + + Given a rotation matrix that performs some coordinate transform, + this function returns the matrix that reverses that trasnform. + + Parameters + ---------- + rotation : RotationMatrix + The rotation matrix to be inverted. + + Returns + ------- + RotationMatrix + The inverse rotation matrix. + """ + return RotationMatrix([ + [rotation.rot[0][0], rotation.rot[1][0], rotation.rot[2][0]], + [rotation.rot[0][1], rotation.rot[1][1], rotation.rot[2][1]], + [rotation.rot[0][2], rotation.rot[1][2], rotation.rot[2][2]] + ]) + def RotateVector(rotation, vector): """Applies a rotation to a vector, yielding a rotated vector. @@ -5123,8 +5145,8 @@ def Rotation_EQJ_ECL(): A rotation matrix that converts EQJ to ECL. """ # ob = mean obliquity of the J2000 ecliptic = 0.40909260059599012 radians. - c = 0.9174821430670688; # cos(ob) - s = 0.3977769691083922; # sin(ob) + c = 0.9174821430670688 # cos(ob) + s = 0.3977769691083922 # sin(ob) return RotationMatrix([ [ 1, 0, 0], [ 0, +c, -s],