如何闭合线段_线段差的最大值的原理

如何闭合线段_线段差的最大值的原理求闭合区域的最外围的线段思路1.找起始点:获取所有的点,找到最左下点(A)点

求闭合区域的最外围的线段思路

如何闭合线段_线段差的最大值的原理

1.找起始点:获取所有的点,找到最左下点(A)点。很关键的点

2.找起始边:首先用邻接链表存储所有点边之间的关系。找到第一条最外围的线段,根据极角来找最外围的线段,注意A是最左下角,所以上面所有连接它的线段和水平角度不会超过180度。以x轴正方向作为向量(1,0),其他向量和它做角度差,用点积求角度。可以找出AB线段。

如何闭合线段_线段差的最大值的原理

 3.找所有外边:通过角度差找最外边。如已经知道第一条外边AB边了,现在对B连接的BJ、BG、BC判断哪一条是接下来的边。通过向量叉积和点积方法,点积只能计算0到180度,无法计算超过180度,这时候利用到叉积,由于我们选的点在左下角,最后找外围线只会逆时针查找,A-B-C-D-E-F-G-H-I-J-K-A。所以0到180度的时候叉积为负,超过180度叉积为正,根据这个去计算其他边AB边的角度,角度最大就是最外边。最终会找到原点A。这样就能找到所有的最外边。

 如何闭合线段_线段差的最大值的原理

//去重
//节点去重
void CubeExportYJKHelper::GetUniquePoints(const vector<iCoord3d>& ptSets, vector<iCoord3d>& needPts)
{
	for (const iCoord3d& pt : ptSets)
	{
		bool exist = false;
		for (const iCoord3d& ic3d : needPts)
		{
			if (abs(ic3d[0] - pt[0]) < TOLERANCE && abs(ic3d[1] - pt[1]) < TOLERANCE)
			{
				exist = true;
				break;
			}
		}
		if (!exist)
			needPts.push_back(pt);
	}
}
//获取最左下角的点
void CubeExportYJKHelper::GetLeftDownPointFromPtSet(const vector<vector<pair<iCoord2d, iCoord2d>>> &areas,vector<iCoord3d> &needPts)
{
    vector<iCoord3d> points;
	//将点提取出来存储,里面会有几个重复的点
    for (const auto &var : areas)
	{
        for_each(var.begin(), var.end(), [&](const pair<iCoord2d, iCoord2d> &pt) 
		{ 
			points.emplace_back(Pt2dTo3d(YJKiCoord2d(pt.first),0));
        });
	}
    //去重
    GetUniquePoints(points, needPts);
    //对点进行排序,得到第一个最下点
    std::sort(needPts.begin(), needPts.end(), [](const iCoord3d &fpt, const iCoord3d &spt) {
		//y轴相同
        if (fpt[1] == spt[1])
            return fpt[0] < spt[0];
        else
            return fpt[1] < spt[1];
    });
}

//获取最外围的线
void CubeExportYJKHelper::GetOutsideLines(const AdjacentListGraph &graph,const int &origin,iVec2d &vec,set<int> & outsideId,
                                          pair<int, int> &lable,bool &tag)
{
    headLNode            headNode = graph.node[lable.first];
    shared_ptr<arcLNode> tempPt = headNode.firstarc;
    //记录点的位置
    int ptAdjvec;
    //判断点积
    double angle = 0;
    //线的id
    int lineId = -1;
    //获取当前点关联的所有其他点
    while (tempPt)
    {
        //如果连接起始点就结束
        if (tempPt->adjvex == lable.second)
        {
            tempPt = tempPt->nextarc;
            continue;
        }
        headLNode otherNode = graph.node[tempPt->adjvex];
        iVec2d    tempVec(otherNode.point[0] - headNode.point[0], otherNode.point[1] - headNode.point[1]);
        //先求两向量叉积,判断角度是否超过180度,由于逆时针找线,所以叉积为负,角度在0到180度,为正角度为180到360
        double crossA = vec.SignZCross(tempVec);
        
        //如果小于0
        if (crossA<=0)
        {
            //求点积
            double dotA = vec.Dot(tempVec);
            //求角度
            double mAngle = acos(dotA / (vec.Length() * tempVec.Length()))*180/PI;
            if (mAngle > angle)
            {
                angle    = mAngle;
                ptAdjvec = tempPt->adjvex; 
                lineId   = tempPt->lineId;
            }  
        }
        else
        {
            //求点积
            double dotA = vec.Dot(tempVec);
            //求角度
            double mAngle = 360 - acos(dotA / (vec.Length() * tempVec.Length())) * 180 / PI;
            if (mAngle > angle)
            {
                angle    = mAngle;
                ptAdjvec = tempPt->adjvex;
                lineId   = tempPt->lineId;
            }
        
        }
        tempPt = tempPt->nextarc;
        continue;  
    }
    //如果最终点是起始点,标记为真,结束循环,找到所有的外围线
    if (ptAdjvec == origin)
    {
        outsideId.insert(lineId);
        tag =true;
    }
    else
    {
        vec = iVec2d(headNode.point[0] - graph.node[ptAdjvec].point[0],
                     headNode.point[1] - graph.node[ptAdjvec].point[1]);
        outsideId.insert(lineId);
        lable = pair<int, int>(ptAdjvec, lable.first);
    }

}

//传入线段集合,获取最外围线段
void CubeExportYJKHelper::GetOutsideLinesFromLineSet(const vector<SegmentLine> &lines,
                                                     const vector<iCoord3d> &   points,
                                                     const iCoord3d &           startPt,
                                                     vector<SegmentLine> &      outside)
{
	//创建邻接链表
    AdjacentListGraph graph;
    graph.edgeNum = static_cast<int>(lines.size());
    graph.vertexNum = static_cast<int>(points.size());
	//存储点
    for_each(points.begin(), points.end(), [&](const iCoord3d points) {
        headLNode hNode(points);
        graph.node.emplace_back(hNode);
		});
	//存储起始点在邻接表的位置
    int originNum(0);
	//存储边的信息
    for (const SegmentLine&line:lines)
	{
		//获取边的两个端点
        vector<iCoord3d> icPt {line.startPt, line.endPt, startPt};
        vector<int>      nums;
		for (const iCoord3d&pt:icPt)
		{
            for (int i = 0; i < graph.vertexNum; ++i)
            {   
				//如果两个点的距离大于1就不是同一个点
                if (pt.DistPtPt(graph.node[i].point) > 1)
                    continue;
                nums.emplace_back(i);
                break;
            }
		}
        iCoord3d sPt(line.startPt), ePt(line.endPt);
		//获取两个点的位置
        int sNum(nums[0]), eNum(nums[1]);
        originNum = nums[2];
		//如果第一点为空
        if (!graph.node[sNum].firstarc)
        {
            std::shared_ptr<arcLNode> arcNode(new arcLNode());
            arcNode->adjvex   = eNum;
            arcNode->lineId   = line.id;
            graph.node[sNum].firstarc  = std::move(arcNode);
        }
        else
        {
            std::shared_ptr<arcLNode> tempNode = graph.node[sNum].firstarc;
			//找到最后一个节点
            while (tempNode->nextarc)
                tempNode = tempNode->nextarc;
            std::shared_ptr<arcLNode> arcNode(new arcLNode());
            arcNode->adjvex           = eNum;
            arcNode->lineId  = line.id;
            tempNode->nextarc          = std::move(arcNode);
		}
        if (!graph.node[eNum].firstarc)
        {
            std::shared_ptr<arcLNode> arcNode(new arcLNode());
            arcNode->adjvex           = sNum;
            arcNode->lineId           = line.id;
            graph.node[eNum].firstarc = std::move(arcNode);
        }
        else
        {
            std::shared_ptr<arcLNode> tempNode = graph.node[eNum].firstarc;
            //找到最后一个节点
            while (tempNode->nextarc)
                tempNode = tempNode->nextarc;
            std::shared_ptr<arcLNode> arcNode(new arcLNode());
            arcNode->adjvex  = sNum;
            arcNode->lineId  = line.id;
            tempNode->nextarc = std::move(arcNode);
        }
	}
	//最外围起始点开始查询,利用和邻边角度差求最外围线
	//找最外边,通过极角方法找最外边
    headLNode originPt = graph.node[originNum];
	//记录当前点所有关联的点形成的线段
    vector<tuple<iCoord3d, int,int>> anglePt;
    shared_ptr<arcLNode>             tempPt = originPt.firstarc; 
    //记录点的位置
    vector<int> ptAdjvec;
    //获取当前点关联的所有其他点
    while (tempPt)
    {
        anglePt.emplace_back(tuple<iCoord3d, int, int>(graph.node[tempPt->adjvex].point, tempPt->adjvex,tempPt->lineId));
        tempPt = tempPt->nextarc;
    }
    double minAngle = 360;
    int    label    = -1;
    int    lineId   = -1;
    iCoord3d point    = originPt.point;
    //最小极角就是最外边
    for_each(anglePt.begin(), anglePt.end(), [&](const tuple<iCoord3d, int,int> pt)
    { 
        iVec2d vec(get<0>(pt)[0] - point[0], get<0>(pt)[1] - point[1]);
        //向量和x轴正方向进行比较
        double angle = vec.Dot(iVec2d(1,0));
        double mAngle = acos(angle / (vec.Length() * iVec2d(1, 0).Length())) * 180 / PI;
        //如果小,记录那个点
        if (mAngle < minAngle)
        {
            minAngle = mAngle;
            label    = get<1>(pt);
            lineId   = get<2>(pt);
        }
    });
    //对起始点和起始边的另一点的访问记录
    graph.node[originNum].visited = true;
    graph.node[label].visited     = true;

    //以这条边去判断最外围的边
    bool endSearch = false;
    //c存第一条边的id
    set<int> outsideId{lineId};
    //第二个点
    iCoord3d sPt = graph.node[label].point;
    iVec2d   vec(point[0]-sPt[0],point[1]-sPt[1]);
    //存点编号,a指向b
    pair<int, int> vecLabel(label, originNum);
    //找到最外围的线,存线的id即可
    while (!endSearch) 
        GetOutsideLines(graph, originNum, vec, outsideId, vecLabel, endSearch);

    //处理最外围的线,去查找
    for (const int& var:outsideId)
    {
        for (const SegmentLine &mLine:lines)
        {
            if (var != mLine.id) continue;

            outside.emplace_back(mLine);
            break;
        }
    }
}

今天的文章如何闭合线段_线段差的最大值的原理分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/78932.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注