几何方式解算偏移
2025-04-11 to 2025-04-12
时隔三个月,现在学习了平面向量,我某天想到新的解算漂移的方法
回忆
之前我要求的是一个三元二次方程组:
是要求的三个值。
然 后,不难看出这三个方程与球的一般方程 相似,只不过一个正负号的区别。所以,该方程组可以看作是三维空间中三个球的交点。
比如之前的这组数据:
其方程组:
绘制转为球方程,绘制图像:
求解
注意
现在我学的还是入门立体几何,以下的表述可能有问题。
已知 三个球,球心为 ,半径为 ,三点坐标:
求 交点 、。
思路
先算出 与 的交平面 和 与 的交平面 。
再计算 和 的交线 。
最后 与 会有两个交点,分别为 、。
符号表式为: 求:
思路:
求两圆交平面
通过法向量和相交圆的圆心 ,计算平面 。
沿 的切面:
易得:
又 法向量与平面上任意向量垂直,所以平面 上任意一点 :
所以平面:
同理:
动态演示(点击下方窗口的右上角第二个选项“Translucent surfaces”可打开半透明):
证明推理无误。
求交面交线
刚刚已求得:
字母对应替换简化为:
然后一通演算:
动态演示(红色为 方程,左侧小箭头可展开方程式):
演算无误
求线与球交点
化简
为
与 联立:
所以这个二次方程的系数为:
编写程序
太累了,直接使用 AI:
#include <Arduino.h>
#include <math.h>
// 定义三维向量结构体
struct Vector3 {
float x, y, z;
};
// 向量运算函数
Vector3 subtract(const Vector3& a, const Vector3& b) {
return {a.x - b.x, a.y - b.y, a.z - b.z};
}
float dot(const Vector3& a, const Vector3& b) {
return a.x * b.x + a.y * b.y + a.z * b.z;
}
Vector3 cross(const Vector3& a, const Vector3& b) {
return {
a.y * b.z - a.z * b.y,
a.z * b.x - a.x * b.z,
a.x * b.y - a.y * b.x
};
}
// 计算两点间距离
float distance(const Vector3& a, const Vector3& b) {
Vector3 diff = subtract(a, b);
return sqrtf(dot(diff, diff));
}
// 几何法求解偏移量,返回两个解
bool solve_offset(const Vector3& O1, const Vector3& O2, const Vector3& O3, float R, Vector3& offset1, Vector3& offset2) {
// 计算平面 α (O1 和 O2)
Vector3 n1 = subtract(O2, O1);
float d1 = (dot(O2, O2) - dot(O1, O1)) / 2.0f;
// 计算平面 β (O1 和 O3)
Vector3 n2 = subtract(O3, O1);
float d2 = (dot(O3, O3) - dot(O1, O1)) / 2.0f;
// 计算交线方向向量
Vector3 dir = cross(n1, n2);
float dir_len = sqrtf(dot(dir, dir));
if (dir_len < 1e-6f) return false; // 平面平行
dir = {dir.x / dir_len, dir.y / dir_len, dir.z / dir_len};
// 寻找交线上一点(设 z = 0)
Vector3 point;
float denom = n1.x * n2.y - n1.y * n2.x;
if (fabsf(denom) > 1e-6f) {
point.x = (n2.y * d1 - n1.y * d2) / denom;
point.y = (n1.x * d2 - n2.x * d1) / denom;
point.z = 0;
} else {
return false; // 无法求解
}
// 直线与球面交点
Vector3 oc = subtract(point, O1);
float a = dot(dir, dir); // 归一化后应为 1
float b = 2.0f * dot(oc, dir);
float c = dot(oc, oc) - R * R;
float discriminant = b * b - 4.0f * a * c;
if (discriminant < 0) return false; // 无实交点
float sqrt_d = sqrtf(discriminant);
float t1 = (-b - sqrt_d) / (2.0f * a);
float t2 = (-b + sqrt_d) / (2.0f * a);
// 计算交点坐标
Vector3 p1 = {point.x + t1 * dir.x, point.y + t1 * dir.y, point.z + t1 * dir.z};
Vector3 p2 = {point.x + t2 * dir.x, point.y + t2 * dir.y, point.z + t2 * dir.z};
// 计算偏移量
offset1 = subtract(p1, O1);
offset2 = subtract(p2, O1);
return true;
}
void setup() {
Serial.begin(115200);
}
void loop() {
// 三个测量点
Vector3 O1 = {0.03f, -0.31f, 8.88f};
Vector3 O2 = {-9.49f, -0.86f, -0.92f};
Vector3 O3 = {0.71f, -10.09f, -0.12f};
float R = 9.8f;
// 第四个球心(从用户提供的数据中选择)
Vector3 O4 = {0.70f, -4.33f, 8.05f}; // 选择 (0.70, -4.33, 8.05)
Vector3 offset1, offset2;
if (solve_offset(O1, O2, O3, R, offset1, offset2)) {
// 计算交点 P 和 Q
Vector3 P = {O1.x + offset1.x, O1.y + offset1.y, O1.z + offset1.z};
Vector3 Q = {O1.x + offset2.x, O1.y + offset2.y, O1.z + offset2.z};
// 计算 O4 到 P 和 Q 的距离
float dist_P = distance(P, O4);
float dist_Q = distance(Q, O4);
// 打印交点 P 和相关信息
Serial.println("交点 P: (" + String(P.x, 6) + ", " + String(P.y, 6) + ", " + String(P.z, 6) + ")");
Serial.println("偏移量 offset1: (" + String(offset1.x, 6) + ", " + String(offset1.y, 6) + ", " + String(offset1.z, 6) + ")");
Serial.println("到 O4 的距离: " + String(dist_P, 6));
// 打印交点 Q 和相关信息
Serial.println("交点 Q: (" + String(Q.x, 6) + ", " + String(Q.y, 6) + ", " + String(Q.z, 6) + ")");
Serial.println("偏移量 offset2: (" + String(offset2.x, 6) + ", " + String(offset2.y, 6) + ", " + String(offset2.z, 6) + ")");
Serial.println("到 O4 的距离: " + String(dist_Q, 6));
// 选择最优解
float error_P = fabsf(dist_P - R);
float error_Q = fabsf(dist_Q - R);
if (error_P < error_Q) {
Serial.println("最优解: 交点 P (offset1)");
} else {
Serial.println("最优解: 交点 Q (offset2)");
}
} else {
Serial.println("未找到有效解。");
}
delay(1000); // 每秒输出一次
}
上传单片机输出
交点 P: (0.295723, -0.331201, -0.916374)
偏移量 offset1: (0.265723, -0.021201, -9.796374)
到 O4 的距离: 9.825971
交点 Q: (-6.383689, -7.117166, 5.953041)
偏移量 offset2: (-6.413689, -6.807166, -2.926960)
到 O4 的距离: 7.895833
最优解: 交点 P (offset1)
与之前算出来的 一样,太棒了!
艰苦历程
从昨天这个点干到现在,四点半睡觉,八点半起床,弄完程序弄数学。现在已经 22:56 了!
作业没写一点,Steam 也没打开,太他妈有意思了。
