3D坐标下,一点在某一线段上的左右方向的判定

3D坐标下,一点在某一线段上的左右方向的判定

代码

C++ 复制代码
#include <iostream>
#include <Eigen/Dense>

#define M_PI 3.1415926

// 计算三点组成平面的参数和变换到XOY平面的变换矩阵
void computePlaneAndTransform(const Eigen::Vector3d& P1, const Eigen::Vector3d& P2, const Eigen::Vector3d& P3,
                              Eigen::Vector4d& planeParams, Eigen::Matrix4d& transformMatrix) {
    // 确保P1在原点
    assert((P1 - Eigen::Vector3d::Zero()).norm() < 1e-6);

    // 计算平面的法向量
    Eigen::Vector3d normal = P2.cross(P3);
    normal.normalize();
    std::cout << "z = " << normal.z() << std::endl;
    if (normal.z() < 0) {
        normal = -1 * normal;
    }
    std::cout << "z2 = " << normal.z() << std::endl;
    // 平面方程为 Ax + By + Cz + D = 0,这里P1在原点,D = 0
    planeParams << normal.x(), normal.y(), normal.z(), 0;

    // 计算旋转矩阵,使得平面的法向量与Z轴对齐
    Eigen::Vector3d zAxis(0, 0, 1);
    double cosTheta = normal.dot(zAxis);
    Eigen::Vector3d crossProduct = normal.cross(zAxis);
    double sinTheta = crossProduct.norm();
    if (sinTheta < 1e-6) {
        // 特殊情况,法向量与Z轴平行或反平行
        if (cosTheta < 0) {
            // 法向量与Z轴反平行
            transformMatrix = Eigen::Matrix4d::Identity();
            transformMatrix.block<3, 3>(0, 0) = Eigen::AngleAxisd(M_PI, Eigen::Vector3d(1, 0, 0)).toRotationMatrix();
        } else {
            // 法向量与Z轴平行
            transformMatrix = Eigen::Matrix4d::Identity();
        }
    } else {
        crossProduct.normalize();
        Eigen::Matrix3d rotationMatrix;
        rotationMatrix << cosTheta + crossProduct.x() * crossProduct.x() * (1 - cosTheta),
                       crossProduct.x()* crossProduct.y()* (1 - cosTheta) - crossProduct.z() * sinTheta,
                       crossProduct.x()* crossProduct.z()* (1 - cosTheta) + crossProduct.y() * sinTheta,

                       crossProduct.y()* crossProduct.x()* (1 - cosTheta) + crossProduct.z() * sinTheta,
                       cosTheta + crossProduct.y() * crossProduct.y() * (1 - cosTheta),
                       crossProduct.y()* crossProduct.z()* (1 - cosTheta) - crossProduct.x() * sinTheta,

                       crossProduct.z()* crossProduct.x()* (1 - cosTheta) - crossProduct.y() * sinTheta,
                       crossProduct.z()* crossProduct.y()* (1 - cosTheta) + crossProduct.x() * sinTheta,
                       cosTheta + crossProduct.z() * crossProduct.z() * (1 - cosTheta);
        transformMatrix.setIdentity();
        transformMatrix.block<3, 3>(0, 0) = rotationMatrix;
    }
}

// 判断点在向量的哪一侧
int determineSide(const Eigen::Vector3d& p4, const Eigen::Vector3d& p5, const Eigen::Vector3d& p6) {
    // 投影到XOY平面
    Eigen::Vector2d p4_2d = p4.head<2>();
    Eigen::Vector2d p5_2d = p5.head<2>();
    Eigen::Vector2d p6_2d = p6.head<2>();

    // 计算向量 P4->P5 和 P4->P6
    Eigen::Vector2d v1 = p5_2d - p4_2d;
    Eigen::Vector2d v2 = p6_2d - p4_2d;

    double crossResult = v1.x() * v2.y() - v1.y() * v2.x();
    std::cout << "crossResult = " << crossResult << std::endl;
    if (crossResult < 0) {
        // 右侧
        return 1;
    } else if (crossResult > 0) {
        // 左侧
        return 2;
    } else {
        // 共线
        return 0;
    }
}

int main() {
    Eigen::Vector3d P1 = Eigen::Vector3d::Zero();
    Eigen::Vector3d P2(10, -10, -13);
    Eigen::Vector3d P3(0, 15, 0);

    Eigen::Vector4d planeParams;
    Eigen::Matrix4d mat;

    computePlaneAndTransform(P1, P2, P3, planeParams, mat);

    // 将点变换到XOY平面
    Eigen::Vector3d P4 = (mat * Eigen::Vector4d(P1.x(), P1.y(), P1.z(), 1)).head<3>();
    Eigen::Vector3d P5 = (mat * Eigen::Vector4d(P2.x(), P2.y(), P2.z(), 1)).head<3>();
    Eigen::Vector3d P6 = (mat * Eigen::Vector4d(P3.x(), P3.y(), P3.z(), 1)).head<3>();
    std::cout << "x, y, z = " << P4.x() << ", " << P4.y() << ", " << P4.z() << std::endl;
    std::cout << "x, y, z = " << P5.x() << ", " << P5.y() << ", " << P5.z() << std::endl;
    std::cout << "x, y, z = " << P6.x() << ", " << P6.y() << ", " << P6.z() << std::endl;

    int side = determineSide(P4, P5, P6);
    std::cout << "P3在向量P1->P2的";
    if (side == 1) {
        std::cout << "右侧" << std::endl;
    } else if (side == 2) {
        std::cout << "左侧" << std::endl;
    } else {
        std::cout << "共线" << std::endl;
    }
    system("pause");
    return 0;
}
相关推荐
创世虚拟世界6 小时前
从零打通 MCP 访问创世虚拟世界CRM的 3D 数据,我搭了一个可直接调用的演示站
3d
李游Leo11 小时前
HarmonyOS 7 + Spatial Recon Kit-C++:3DGS 高斯参数的非有限值隔离与可渲染性门禁【鸿蒙心迹】
开发语言·c++·3d·harmonyos
迁移科技11 小时前
小体积蕴含大能量:Epic Eye Pixel Mini轻量化相机的应用美学
人工智能·3d·自动化·视觉检测
Martina_032114 小时前
同一片森林换个镜头就忽冷忽暖?用6步统一曝光、LUT与相机后处理
人工智能·游戏·数学建模·3d·自然语言处理·aigc·游戏策划
Better Bench15 小时前
奇异值分解(SVD)在3D骨骼旋转中的应用:原理与实现
3d·人体姿态估计·骨骼关键点
追烽少年x16 小时前
从零构建一个3D点云预览器:Python + PySide6 + pyqtgraph 实战
python·3d
西红柿炖牛腩3542 天前
Three.js 模型体积优化:Draco/Meshopt 压缩与 DRACOLoader 配置的 4 个步骤
javascript·3d·性能优化
JAI科研2 天前
CT重建(二) | 3D高斯泼溅:实时渲染的革命
图像处理·人工智能·计算机视觉·3d·视觉检测·ct重建
李游Leo2 天前
HarmonyOS 7 + Spatial Recon Kit-C++:3DGS 输入帧内参与位姿的版本一致性门禁【鸿蒙心迹】
c++·3d·harmonyos
HwJack202 天前
【共创稿事节】HarmonyOS 7空间信息层级:焦点、景深与注意力引导
3d·华为·harmonyos·空间计算