Bootstrap

二维平面中二维向量的叉乘 得到的向量,x、y方向上的分量必定为0

  • 二维平面中二维向量的叉乘 得到的向量,x、y方向上的分量必定为0,
    所以可以用z的值判断一个向量在另一个向量的左侧还是右侧。
    在这里插入图片描述
  • 推导(其实这个是二维上的定义,先用二维的推出来的三维,我用三维反过来理解二维。。):
    由于z1 = z2 = 0,那么 axb = k(x1y2 - y1x2)
    只存在z轴上的分量。
//没用的代码增加了
#define _VecTypeName double
class Solution {
public:
// -------手写通用矩阵运算库----------
    // 点乘
    template <typename T>
    T dot(vector<T>& vec2_1 ,vector<T>& vec2_2){
        return vec2_1[0] * vec2_2[0] + vec2_1[1] * vec2_2[1];
    }
    // 叉乘,这里只要它z轴上的分量
    template <typename T>
    T cross(vector<T>& vec2_1 ,vector<T>& vec2_2){
        return vec2_1[0] * vec2_2[1] - vec2_1[1] * vec2_2[0];
    }
    // 归一化
    void normalize(vector<_VecTypeName>& vec2){
        if (vec2[0] == 0 || vec2[1] == 0)
            return;
        _VecTypeName sqx = vec2[0] * vec2[0];
        _VecTypeName sqy = vec2[1] * vec2[1];
        //cout << vec2[0] << " *in* " << vec2[1];
        vec2[0] = sqrt(sqx / (sqx + sqy)) * (vec2[0] / abs(vec2[0]));
        vec2[1] = sqrt(sqy / (sqx + sqy)) * (vec2[1] / abs(vec2[1]));
        //cout << vec2[0] << " *out* " << vec2[1];
    }
    // 构造 point1 指向 point2 的二维单位向量
    template <typename T>
    void makeVec2(vector<T>& vec2, vector<int>& point1, vector<int>& point2){
        vec2[0] = T(point2[0] - point1[0]);
        vec2[1] = T(point2[1] - point1[1]);
        //normalize<T>(vec2);
    }
    // 向量叠加
    void addVec(vector<_VecTypeName>& vec2,vector<_VecTypeName>& vec2_1 ,vector<_VecTypeName>& vec2_2){
        vec2[0] = vec2_1[0] + vec2_2[0];
        vec2[1] = vec2_1[1] + vec2_2[1];
    }
    // 获取xmin的点
    void getXMinPoint(vector<int>& point,vector<vector<int>>& trees){
        int xmin = INT_MAX;
        for (unsigned int i = 0; i < trees.size(); ++i){
            int x = trees[i][0];
            if (xmin > x){
                xmin = x;
                point[0] = trees[i][0];
                point[1] = trees[i][1];
            }
        }
    }
    // 获取以x+轴为方向的向量
    template <typename T>
    void getPolarCoordinates(vector<T>& vec2){
        vec2[0] = 1;
        vec2[1] = 0;
    }
    // 判断两个位置或向量
    template <typename T>
    bool equalVec2(T& point1, T& point2){
        return point1[0] == point2[0] and point1[1] == point2[1];
    }
    // 
    template <typename T>
    int setLevelFromDotAndCross(T& dotdata, T& crossdata){
        int leveldata = 0;
        if (crossdata < 0)
            leveldata = 5;
        else if (crossdata == 0 && dotdata > 0)
            leveldata = 4;
        else if (crossdata > 0)
            leveldata = 3;
        else if (crossdata == 0 && dotdata <= 0)
            leveldata = 2;
        return leveldata;
    }
    // 比较逆时针度数
    template <typename T>
    bool compareDotAndCross(T& dotdata1, T& crossdata1, T& dotdata2, T& crossdata2, T& ori_dotdata1, T& ori_dotdata2){
        /* 
        在逆时针上判断,cross < 0 的最大 (内部比较 点积越小逆时针角度越大),
        其次是 cross == 0 && dotdata > 0 的,
        再然后是 cross < 0 的 (内部比较 点积越大逆时针角度越大),
        再然后是 cross == 0 && dotdata <= 0 的
        */
        int leveldata1 = setLevelFromDotAndCross<T>(dotdata1,crossdata1);
        int leveldata2 = setLevelFromDotAndCross<T>(dotdata2,crossdata2);
        // 叉积异号 直接得出结果
        if (leveldata1 != leveldata2)
            return leveldata1 > leveldata2;
        // 叉积同号 y-轴方向 点积越小逆时针角度越大
        if (leveldata1 == 5)
            return dotdata1 < dotdata2;
        // 同向要距离近的
        if (leveldata1 == 4)
            return ori_dotdata1 < ori_dotdata2;
        // 反向要距离近的
        if (leveldata1 == 2)
            return ori_dotdata1 > ori_dotdata2;
        // 叉积同号 y+轴方向 点积越小逆时针角度越小
        return dotdata1 > dotdata2;
    }

// -------手写通用矩阵运算库----------
    // 寻找凸多边形 可以肯定 xmin xmax ymin ymax的点 在凸包上
    // 那么先用Jarvis算法,取xmin
    vector<vector<int>> outerTrees(vector<vector<int>>& trees) {
        // 至少有三个点才能构成两个向量
        if (trees.size() <= 2) return trees;
        vector<vector<int>> cp_tree;
        for (unsigned int i = 0; i < trees.size(); ++i){
            vector<int> cp_data(2,0);
            cp_data[0] = trees[i][0];
            cp_data[1] = trees[i][1];
            cp_tree.push_back(cp_data);
        }
        vector<vector<int>> res;
        // 最开始的法向量,[1,0],之后每得到一个点法向量变化到上一个向量
        vector<_VecTypeName> axis_x(2,0);
        getPolarCoordinates<_VecTypeName>(axis_x);
        vector<int> point(2,0);
        getXMinPoint(point,trees);
        res.push_back(point);
        while(!(
            res.size() > 1 and equalVec2<vector<int>>(*(res.end() - 1),*(res.begin()))
            )){
            // 最弱情况指向贴着x-轴的左上角角度
            _VecTypeName crossdata1 = 1;
            _VecTypeName dotdata1 = -999;
            // ori用来记录原始长度,算最近的点
            _VecTypeName ori_dotdata1 = 0;
            vector<int> pi(2,0);
            int index = -1;
            for (unsigned int i = 0; i < trees.size(); ++i){
                // 因为本算法每次找到最优解没有回溯,所以用完的直接扔掉不再参与运算。
                if (equalVec2<vector<int>>(*(res.end() - 1),trees[i])){
                    continue;
                }
                vector<_VecTypeName> vecp(2,0);
                makeVec2<_VecTypeName>(vecp,*(res.end() - 1),trees[i]);
                _VecTypeName ori_dotdata2 = dot<_VecTypeName>(axis_x,vecp);
                normalize(vecp);
                _VecTypeName crossdata2 = cross<_VecTypeName>(axis_x,vecp);
                _VecTypeName dotdata2 = dot<_VecTypeName>(axis_x,vecp);
                if (!compareDotAndCross<_VecTypeName>(dotdata1,crossdata1,dotdata2,crossdata2,ori_dotdata1,ori_dotdata2)){
                    // if (trees[i][0] == 4 and trees[i][1] == 0 and res.size() == 4)
                    // {
                    //     cout << "start" << endl << dotdata1 << " " << crossdata1 << endl << dotdata2 << " " << crossdata2 << endl << "end" << endl;
                    //     cout << "curpos [ " << axis_x[0] << axis_x[1] << " ] thispos [ " << vecp[0] << vecp[1] << " ]" << endl;
                    // }
                    // else{
                    //     cout << "lastpos [ " << vecp[0] << vecp[1] << " ]" << endl;
                    // }
                    crossdata1 = crossdata2;
                    dotdata1 = dotdata2;
                    ori_dotdata1 = ori_dotdata2;
                    pi[0] = trees[i][0];
                    pi[1] = trees[i][1];
                    index = i;
                }
            }
            if (index >= 0){
                makeVec2<_VecTypeName>(axis_x,*(res.end() - 1),pi);
                normalize(axis_x);
                res.push_back(pi);
                cout << index << " " << trees.size() << endl;
                trees.erase(trees.begin() + index);
            }
            else{
                return cp_tree;
            }
        }
        res.erase(res.end()-1);
        return res;
    }
};

/*
取[1,1] [m,n]遍历其他顶点,
先用叉乘确定法向量的方向,决定在左边还是在右边,
再用点积确定夹角,重合是1,逆向是-1,负数角度大,正数角度小
*/
;