-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
591,935 additions
and
164 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,271 @@ | ||
<!-- | ||
Turns rover motion files (SVF and RVF) into JSON arrays. | ||
Saves into JSON file. | ||
To do: plot data with plotly, see traverse2d.html | ||
--> | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>RVF File Processor & 2D Viewer</title> | ||
|
||
</head> | ||
<body> | ||
<div class="container"> | ||
<div class="controls"> | ||
<h2>File Input</h2> | ||
<div class="file-input"> | ||
<label>Master SVF:</label><br> | ||
<input type="file" id="masterFile" accept=".svf"> | ||
</div> | ||
<div class="file-input"> | ||
<label>Secondary RVF Files:</label><br> | ||
<input type="file" id="secondaryFiles" accept=".rvf" multiple> | ||
</div> | ||
<button id="saveButton" style="margin-top: 20px;">Salva dati su file</button><br> | ||
<button id="processButton" disabled>ELABORA</button> | ||
</div> | ||
|
||
</div> | ||
|
||
<script> | ||
let masterData = null; | ||
let secondaryData = []; | ||
let siteOffsets = []; | ||
let drives = {}; | ||
|
||
// Funzione per convertire quaternione in Euler angles (yaw, pitch, roll) | ||
function quaternionToEuler(q) { | ||
let yaw = Math.atan2(2*(q.s*q.v3 + q.v1*q.v2), 1 - 2*(q.v2*q.v2 + q.v3*q.v3)); | ||
let pitch = Math.asin(2*(q.s*q.v2 - q.v3*q.v1)); | ||
let roll = Math.atan2(2*(q.s*q.v1 + q.v2*q.v3), 1 - 2*(q.v1*q.v1 + q.v2*q.v2)); | ||
return { yaw, pitch, roll }; | ||
} | ||
|
||
// Event listeners per i file | ||
document.getElementById('masterFile').addEventListener('change', async (e) => { | ||
const file = e.target.files[0]; | ||
const text = await file.text(); | ||
masterData = new DOMParser().parseFromString(text, 'text/xml'); | ||
updateProcessButton(); | ||
processMasterFile(); | ||
}); | ||
|
||
// Event listener per i file secondari | ||
document.getElementById('secondaryFiles').addEventListener('change', async (e) => { | ||
secondaryData = []; | ||
|
||
// Ordina i file in base al nome | ||
const files = Array.from(e.target.files).sort((a, b) => a.name.localeCompare(b.name)); | ||
|
||
for (let file of files) { | ||
const text = await file.text(); | ||
console.log(file.name); // Per verifica | ||
secondaryData.push(new DOMParser().parseFromString(text, 'text/xml')); | ||
} | ||
|
||
updateProcessButton(); | ||
processSecondaryFiles(); | ||
}); | ||
|
||
|
||
function updateProcessButton() { | ||
button = document.getElementById('processButton'); | ||
button.disabled = !(masterData && secondaryData.length > 0 ); | ||
button = document.getElementById('saveButton'); | ||
saveButton.disabled = !(masterData && secondaryData.length > 0 ); | ||
} | ||
|
||
function processMasterFile() { | ||
siteOffsets = []; | ||
const solutions = masterData.getElementsByTagName('solution'); | ||
let cumulativeOffset = { x: 0, y: 0, z: 0 }; | ||
|
||
for (let solution of solutions) { | ||
//console.log("solution", solution); | ||
if (solution.getAttribute('name') === 'SITE_FRAME') { | ||
const index1 = parseInt(solution.getAttribute('index1')); | ||
//console.log(" site found", index1); | ||
const offset = solution.getElementsByTagName('offset')[0]; | ||
//console.log(" offset=", offset); | ||
const relativeOffset = { | ||
x: parseFloat(offset.getAttribute('x')), | ||
y: parseFloat(offset.getAttribute('y')), | ||
z: parseFloat(offset.getAttribute('z')) | ||
}; | ||
//console.log(" relativeOffset=", relativeOffset); | ||
|
||
cumulativeOffset = { | ||
x: cumulativeOffset.x + relativeOffset.x, | ||
y: cumulativeOffset.y + relativeOffset.y, | ||
z: cumulativeOffset.z + relativeOffset.z | ||
}; | ||
|
||
//console.log(" cumulativeOffset=", cumulativeOffset); | ||
siteOffsets.push({ | ||
index1, | ||
relativeOffset, | ||
cumulativeOffset: {...cumulativeOffset} | ||
}); | ||
} | ||
} | ||
} | ||
|
||
function processSecondaryFiles() { | ||
drives = {}; | ||
|
||
// Per ogni documento XML secondario | ||
for (let doc of secondaryData) { | ||
//console.log(doc) | ||
const solutions = doc.getElementsByTagName('solution'); | ||
// Per ogni solution nel documento | ||
for (let solution of solutions) { | ||
if (solution.getAttribute('name') === 'ROVER_FRAME') { | ||
const site = parseInt(solution.getAttribute('index1')); | ||
const drive = parseInt(solution.getAttribute('index2')); | ||
|
||
// Ottieni offset e orientamento dalla solution | ||
const offset = solution.getElementsByTagName('offset')[0]; | ||
const orientation = solution.getElementsByTagName('orientation')[0]; | ||
|
||
// Crea oggetto quaternione dai dati | ||
const quaternion = { | ||
s: parseFloat(orientation.getAttribute('s')), | ||
v1: parseFloat(orientation.getAttribute('v1')), | ||
v2: parseFloat(orientation.getAttribute('v2')), | ||
v3: parseFloat(orientation.getAttribute('v3')) | ||
}; | ||
|
||
// Cerca l'offset cumulativo corrispondente al site | ||
let siteOffset = { x: 0, y: 0, z: 0 }; // valore di default | ||
|
||
if (site>0) { | ||
siteOffset = siteOffsets[site-1].cumulativeOffset; | ||
} | ||
|
||
// console.log(" siteOffset=", siteOffset); | ||
|
||
// Crea oggetto con l'offset del drive | ||
const driveOffset = { | ||
x: parseFloat(offset.getAttribute('x')), | ||
y: parseFloat(offset.getAttribute('y')), | ||
z: parseFloat(offset.getAttribute('z')) | ||
}; | ||
|
||
// Calcola l'offset totale sommando siteOffset e driveOffset | ||
const totalOffset = { | ||
x: siteOffset.x + driveOffset.x, | ||
y: siteOffset.y + driveOffset.y, | ||
z: siteOffset.z + driveOffset.z | ||
}; | ||
|
||
// Inizializza l'oggetto per il site se non esiste | ||
if (!drives[site]) { | ||
drives[site] = {}; | ||
} | ||
|
||
// Memorizza tutti i dati per questa combinazione site/drive | ||
drives[site][drive] = { | ||
offset: driveOffset, | ||
quaternion: quaternion, | ||
euler: quaternionToEuler(quaternion), | ||
totalOffset: totalOffset | ||
}; | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
||
|
||
// Funzione di debug | ||
function placeMarkers() { | ||
console.log("Inizio debugWithBoxes"); | ||
|
||
|
||
|
||
} | ||
|
||
|
||
/** | ||
* Calcola la differenza tra i campi euler e totalOffset di due elementi dell'array drives | ||
* @param {Object} drives - Array bidimensionale con indici site e drive | ||
* @param {string|number} site1 - Primo indice site | ||
* @param {string|number} drive1 - Primo indice drive | ||
* @param {string|number} site2 - Secondo indice site | ||
* @param {string|number} drive2 - Secondo indice drive | ||
* @returns {Object} Oggetto contenente le differenze calcolate | ||
*/ | ||
function calculateDrivesDifferences(site1, drive1, site2, drive2) { | ||
// Costante per convertire da radianti a gradi | ||
const RAD_TO_DEG = 180 / Math.PI; | ||
|
||
// Ottieni i due elementi dall'array | ||
const element1 = drives[site1][drive1]; | ||
const element2 = drives[site2][drive2]; | ||
|
||
// Calcola le differenze per gli angoli di Euler e converti in gradi | ||
const eulerDiffRad = { | ||
yaw: (element1.euler.yaw - element2.euler.yaw), | ||
pitch: (element1.euler.pitch - element2.euler.pitch), | ||
roll: (element1.euler.roll - element2.euler.roll) | ||
}; | ||
|
||
const eulerDiffDeg = { | ||
yaw: (element1.euler.yaw - element2.euler.yaw) * RAD_TO_DEG, | ||
pitch: (element1.euler.pitch - element2.euler.pitch) * RAD_TO_DEG, | ||
roll: (element1.euler.roll - element2.euler.roll) * RAD_TO_DEG | ||
}; | ||
|
||
// Calcola le differenze per totalOffset | ||
const totalOffsetDiff = { | ||
x: element1.totalOffset.x - element2.totalOffset.x, | ||
y: element1.totalOffset.y - element2.totalOffset.y, | ||
z: element1.totalOffset.z - element2.totalOffset.z | ||
}; | ||
|
||
return { | ||
eulerDiffRad, | ||
eulerDiffDeg, | ||
totalOffsetDiff | ||
}; | ||
} | ||
|
||
|
||
// Funzione per salvare i dati su un file JSON | ||
function saveDataToFile(data, filename) { | ||
// Converti i dati in una stringa JSON | ||
const jsonData = "const drives = " + JSON.stringify(data, null, 2); | ||
|
||
// Crea un blob con i dati | ||
const blob = new Blob([jsonData], { type: "application/json" }); | ||
|
||
// Crea un URL per il download | ||
const url = window.URL.createObjectURL(blob); | ||
|
||
// Crea un elemento <a> per il download | ||
const a = document.createElement("a"); | ||
a.href = url; | ||
a.download = filename; | ||
|
||
// Attiva il download | ||
a.click(); | ||
|
||
// Libera la memoria | ||
window.URL.revokeObjectURL(url); | ||
} | ||
|
||
document.getElementById("saveButton").addEventListener("click", () => { | ||
saveDataToFile(drives, "drives.js"); | ||
}); | ||
|
||
document.getElementById("processButton").addEventListener("click", () => { | ||
placeMarkers(); | ||
}); | ||
|
||
|
||
|
||
</script> | ||
</body> | ||
</html> |
Oops, something went wrong.