2025-08-18 14:13:40 +02:00
|
|
|
|
<template>
|
|
|
|
|
|
<v-card v-if="comparison" class="ma-1">
|
|
|
|
|
|
<v-card-title>Comparison Summary: Baseline {{ baseline.pid }} vs Monitor {{ monitor.pid }}</v-card-title>
|
|
|
|
|
|
<v-card-text>
|
|
|
|
|
|
<v-row>
|
|
|
|
|
|
<v-col cols="12" md="6">
|
|
|
|
|
|
<h3>Deviation Statistics</h3>
|
|
|
|
|
|
<v-simple-table dense>
|
|
|
|
|
|
<template v-slot:default>
|
|
|
|
|
|
<thead>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<th>Metric</th>
|
2025-08-19 19:28:19 +02:00
|
|
|
|
<th>I (m)</th>
|
|
|
|
|
|
<th>J (m)</th>
|
2025-08-18 14:13:40 +02:00
|
|
|
|
</tr>
|
|
|
|
|
|
</thead>
|
|
|
|
|
|
<tbody>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td>Mean (μ)</td>
|
|
|
|
|
|
<td>{{ comparison['μ'][0].toFixed(3) }}</td>
|
|
|
|
|
|
<td>{{ comparison['μ'][1].toFixed(3) }}</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td>Std Dev (σ)</td>
|
|
|
|
|
|
<td>{{ comparison['σ'][0].toFixed(3) }}</td>
|
|
|
|
|
|
<td>{{ comparison['σ'][1].toFixed(3) }}</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td>RMS</td>
|
|
|
|
|
|
<td>{{ comparison.rms[0].toFixed(3) }}</td>
|
|
|
|
|
|
<td>{{ comparison.rms[1].toFixed(3) }}</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</tbody>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</v-simple-table>
|
|
|
|
|
|
|
2025-08-19 19:28:19 +02:00
|
|
|
|
<h3 class="mt-4">Error distribution</h3>
|
2025-08-18 14:13:40 +02:00
|
|
|
|
<ul>
|
2025-08-19 19:28:19 +02:00
|
|
|
|
<li title="Relative to I-axis positive direction">Primary Direction: {{ (comparison.primaryDirection * 180 / Math.PI).toFixed(2) }}°</li>
|
|
|
|
|
|
<li>Anisotropy: {{ comparison.anisotropy.toFixed(2) }}</li>
|
|
|
|
|
|
<li title="Length of the semi-major axis of the error ellipse">Semi-Major Axis: {{ semiMajorAxis.toFixed(2) }} m</li>
|
|
|
|
|
|
<li title="Length of the semi-minor axis of the error ellipse">Semi-Minor Axis: {{ semiMinorAxis.toFixed(2) }} m</li>
|
|
|
|
|
|
<li title="Area of the error ellipse">Error Ellipse Area: {{ ellipseArea.toFixed(2) }} m²</li>
|
2025-08-18 14:13:40 +02:00
|
|
|
|
</ul>
|
|
|
|
|
|
|
2025-08-19 19:28:19 +02:00
|
|
|
|
<h3 class="mt-4">Counts</h3>
|
2025-08-18 14:13:40 +02:00
|
|
|
|
<ul>
|
2025-08-19 19:28:19 +02:00
|
|
|
|
<li title="Unique line / point pairs found in both projects">Common Points: {{ comparison.common }}</li>
|
|
|
|
|
|
<li title="Total number of points compared, including reshoots, infills, etc.">Comparison Length: {{ comparison.length }}</li>
|
|
|
|
|
|
<li title="Number of points in the baseline project">Baseline Points: {{ comparison.baselineLength }} (Unique: {{ comparison.baselineUniqueLength }})</li>
|
|
|
|
|
|
<li title="Number of points in the monitor project">Monitor Points: {{ comparison.monitorLength }} (Unique: {{ comparison.monitorUniqueLength }})</li>
|
2025-08-18 14:13:40 +02:00
|
|
|
|
</ul>
|
2025-08-19 19:28:19 +02:00
|
|
|
|
|
|
|
|
|
|
<p class="mt-3" title="Date and time when the comparison was last performed">Computation timestamp: {{ new Date(comparison.tstamp).toLocaleString() }}</p>
|
2025-08-18 14:13:40 +02:00
|
|
|
|
</v-col>
|
|
|
|
|
|
|
|
|
|
|
|
<v-col cols="12" md="6">
|
|
|
|
|
|
<h3>Error Ellipse</h3>
|
|
|
|
|
|
<svg width="300" height="300" style="border: 1px solid #ccc;">
|
|
|
|
|
|
<g :transform="`translate(150, 150) scale(${ellipseScale})`">
|
|
|
|
|
|
<line x1="0" y1="-150" x2="0" y2="150" stroke="lightgray" stroke-dasharray="5,5"/>
|
|
|
|
|
|
<line x1="-150" y1="0" x2="150" y2="0" stroke="lightgray" stroke-dasharray="5,5"/>
|
|
|
|
|
|
<ellipse
|
|
|
|
|
|
:rx="Math.sqrt(comparison.eigenvalues[0])"
|
|
|
|
|
|
:ry="Math.sqrt(comparison.eigenvalues[1])"
|
|
|
|
|
|
:transform="`rotate(${ellipseAngle})`"
|
|
|
|
|
|
fill="none"
|
|
|
|
|
|
stroke="blue"
|
|
|
|
|
|
stroke-width="2"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<line
|
|
|
|
|
|
:x1="0"
|
|
|
|
|
|
:y1="0"
|
|
|
|
|
|
:x2="Math.sqrt(comparison.eigenvalues[0]) * Math.cos(ellipseRad)"
|
|
|
|
|
|
:y2="Math.sqrt(comparison.eigenvalues[0]) * Math.sin(ellipseRad)"
|
|
|
|
|
|
stroke="red"
|
|
|
|
|
|
stroke-width="2"
|
|
|
|
|
|
arrow-end="classic-wide-long"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<line
|
|
|
|
|
|
:x1="0"
|
|
|
|
|
|
:y1="0"
|
|
|
|
|
|
:x2="Math.sqrt(comparison.eigenvalues[1]) * Math.cos(ellipseRad + Math.PI / 2)"
|
|
|
|
|
|
:y2="Math.sqrt(comparison.eigenvalues[1]) * Math.sin(ellipseRad + Math.PI / 2)"
|
|
|
|
|
|
stroke="green"
|
|
|
|
|
|
stroke-width="2"
|
|
|
|
|
|
arrow-end="classic-wide-long"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</g>
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
<p class="text-caption">Ellipse scaled for visibility (factor: {{ ellipseScale.toFixed(1) }}). Axes represent sqrt(eigenvalues).</p>
|
|
|
|
|
|
</v-col>
|
|
|
|
|
|
</v-row>
|
|
|
|
|
|
</v-card-text>
|
|
|
|
|
|
</v-card>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
export default {
|
|
|
|
|
|
name: "DougalGroupComparisonSummary",
|
|
|
|
|
|
|
|
|
|
|
|
props: {
|
|
|
|
|
|
baseline: { type: Object, required: true },
|
|
|
|
|
|
monitor: { type: Object, required: true },
|
|
|
|
|
|
comparison: { type: Object, required: true }
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
data () {
|
|
|
|
|
|
return {
|
|
|
|
|
|
};
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
computed: {
|
|
|
|
|
|
|
|
|
|
|
|
ellipseAngle () {
|
|
|
|
|
|
if (!this.comparison) return 0;
|
|
|
|
|
|
const ev = this.comparison.eigenvectors[0];
|
|
|
|
|
|
return Math.atan2(ev[1], ev[0]) * 180 / Math.PI;
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
ellipseRad () {
|
|
|
|
|
|
return this.ellipseAngle * Math.PI / 180;
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
ellipseRx () {
|
|
|
|
|
|
if (!this.comparison) return 0;
|
|
|
|
|
|
return Math.sqrt(this.comparison.eigenvalues[0]) * this.ellipseScale;
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
ellipseRy () {
|
|
|
|
|
|
if (!this.comparison) return 0;
|
|
|
|
|
|
return Math.sqrt(this.comparison.eigenvalues[1]) * this.ellipseScale;
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
ellipseScale () {
|
|
|
|
|
|
if (!this.comparison) return 1;
|
|
|
|
|
|
const maxSigma = Math.max(
|
|
|
|
|
|
Math.sqrt(this.comparison.eigenvalues[0]),
|
|
|
|
|
|
Math.sqrt(this.comparison.eigenvalues[1])
|
|
|
|
|
|
);
|
|
|
|
|
|
const maxMu = Math.max(
|
|
|
|
|
|
Math.abs(this.comparison['μ'][0]),
|
|
|
|
|
|
Math.abs(this.comparison['μ'][1])
|
|
|
|
|
|
);
|
2025-08-19 19:28:19 +02:00
|
|
|
|
//const maxExtent = maxMu + 3 * maxSigma;
|
|
|
|
|
|
const maxExtent = 20;
|
2025-08-18 14:13:40 +02:00
|
|
|
|
return 100 / maxExtent; // Adjust scale to fit within ~200 pixels diameter
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-08-19 19:28:19 +02:00
|
|
|
|
ellipseArea () {
|
|
|
|
|
|
if (!this.comparison) return 0;
|
|
|
|
|
|
const a = Math.sqrt(this.comparison.eigenvalues[0]);
|
|
|
|
|
|
const b = Math.sqrt(this.comparison.eigenvalues[1]);
|
|
|
|
|
|
return Math.PI * a * b;
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
semiMajorAxis () {
|
|
|
|
|
|
if (!this.comparison) return 0;
|
|
|
|
|
|
return Math.max(
|
|
|
|
|
|
Math.sqrt(this.comparison.eigenvalues[0]),
|
|
|
|
|
|
Math.sqrt(this.comparison.eigenvalues[1])
|
|
|
|
|
|
);
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
semiMinorAxis () {
|
|
|
|
|
|
if (!this.comparison) return 0;
|
|
|
|
|
|
return Math.min(
|
|
|
|
|
|
Math.sqrt(this.comparison.eigenvalues[0]),
|
|
|
|
|
|
Math.sqrt(this.comparison.eigenvalues[1])
|
|
|
|
|
|
);
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-08-18 14:13:40 +02:00
|
|
|
|
meanX () {
|
|
|
|
|
|
return this.comparison ? this.comparison['μ'][0] : 0;
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
meanY () {
|
|
|
|
|
|
return this.comparison ? this.comparison['μ'][1] : 0;
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
ellipseViewBox () {
|
|
|
|
|
|
return '-150 -150 300 300';
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|