几何尺寸与公差论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 20|回复: 0

直线的拾取-拍2张 图循环执行时长度扰动几十微米

[复制链接]
发表于 昨天 11:08 | 显示全部楼层 |阅读模式
#include "pch.h"
#include "EleLine.h"
#include "FuncBase.h"
#include "MathHelper.h"
#include "LineConstructLog.h"
#include "ElePlane.h"
#include "EleGap.h"
#include "ElePointCloud.h"
#include "Alignment.h"
#include <algorithm>
#include "EleEllipse.h"
#include <unordered_set>
/// <summary>
/// 初始化
/// </summary>
/// <param name="count"></param>
/// <param name="uid"></param>
/// <param name="vectors"></param>
void EleLine::EleInit(int count, string uid, ShapeRecognition vectors)
{
        CElementBase::Init();
        this->m_strElementUid = uid;
        this->nType = ELE_LINE;
        this->m_strTypeName = "Line";
        this->m_nIndex = count + 1;
        if (vectors.IsScan)
        {
                mcs_Start = vectors.LeftTopPo;
                mcs_End = vectors.BottomRightPo;
                m_pMCS->McsPosition = (vectors.LeftTopPo.XYZ() + vectors.BottomRightPo.XYZ()) * 0.5;
                Length = mcs_Start.Distance(mcs_End);
                PointF = vectors.McsPointF;
                this->m_bIsScan = vectors.IsScan;
        }
}

/// <summary>
/// 克隆
/// </summary>
/// <returns></returns>
CElementBase* EleLine::Clone()
{
        CElementBase* ptr = new EleLine(*this);
        ptr->Init();
        ptr->m_pMCS->McsPosition = this->m_pMCS->McsPosition;
        ptr->m_pMCS->McsLeftPoint = this->m_pMCS->McsLeftPoint;
        ptr->m_pMCS->McsRightPoint = this->m_pMCS->McsRightPoint;
        ptr->m_pPCS->PcsPosition = this->m_pPCS->PcsPosition;
        return ptr;
}

/// <summary>
/// 绘制
/// </summary>
/// <returns></returns>
Handle(MyInteractiveObject) EleLine::Draw(double zoomFactor)
{
        gp_Pnt startP = this->mcs_Start;
        gp_Pnt endP = this->mcs_End;
        if (startP.XYZ().IsEqual(endP.XYZ(), 1.0e-9))
                return nullptr;
        //处理特征偏移
        auto points = FuncBase::ElementOffset(this);
        if (points.size() > 0)
        {
                startP = points[0];
                endP = points[1];
        }
        TopoDS_Vertex V1 = BRepBuilderAPI_MakeVertex(startP);
        TopoDS_Vertex V2 = BRepBuilderAPI_MakeVertex(endP);
        TopoDS_Shape aShape = BRepBuilderAPI_MakeEdge(V1, V2);
        Handle(MyInteractiveObject) aisLine = new MyInteractiveObject(aShape);
        return aisLine;
}


Handle(MyInteractiveObject) EleLine::DrawLable(string name, gp_Pnt& firstPt)
{
        vector<gp_Pnt> myPoints = PointF;
        if (myPoints.size() < 3)
        {
                myPoints.clear();
                myPoints.push_back(this->mcs_Start);
                myPoints.push_back(this->mcs_End);
                myPoints.push_back(this->m_pMCS->McsPosition);
        }
        int randomIndex = GenerateRandomIndex(0, static_cast<int>(myPoints.size()) - 1);
        gp_Pnt startPo = GetSubPoint(myPoints.at(randomIndex));
        startPo = FuncBase::GetMatrixPoint(this, startPo);
        // 角度参数θ
        double theta = GenerateRandomAngle();  // 比如θ = 45度,即π/4
        // 计算圆上点的坐标
        double x = startPo.X() + 3 * cos(theta);
        double y = startPo.Y() + 3 * sin(theta);
        gp_Pnt pointCir = gp_Pnt(x, y, startPo.Z());

        gp_Vec avgVec = gp_Vec(startPo, pointCir).Normalized();

        if (avgVec.Y() == 0) //平行与X轴
        {
                avgVec = gp_Vec(0, 1, 0);
        }
        else if (avgVec.X() == 0)  //平行与Y轴
        {
                avgVec = gp_Vec(1, 0, 0);
        }
        gp_Pnt endPo1 = startPo.XYZ() + (avgVec * 4).XYZ();
        gp_Pnt lablePos = startPo.XYZ() + (avgVec * 4.5).XYZ();
        firstPt = startPo;
        TopoDS_Vertex V1 = BRepBuilderAPI_MakeVertex(startPo);
        TopoDS_Vertex V2 = BRepBuilderAPI_MakeVertex(endPo1);
        TopoDS_Shape aShape = BRepBuilderAPI_MakeEdge(V1, V2);
        Handle(MyInteractiveObject) eleLable = new MyInteractiveObject(aShape);
        Handle(AIS_TextLabel) lable = new AIS_TextLabel();
        lable->SetPosition(lablePos);
        lable->SetZoomable(false);
        lable->SetColor(Quantity_NOC_YELLOW);
        TCollection_ExtendedString tostr;
        Resource_Unicode::ConvertGBToUnicode(name.c_str(), tostr);
        lable->SetText(tostr);
        eleLable->SetTextLabel(lable);
        return eleLable;
}

/// <summary>
/// 获取最近点
/// </summary>
/// <param name="point"></param>
/// <returns></returns>
gp_Pnt EleLine::GetSubPoint(gp_Pnt point)
{
        gp_Vec dirction = gp_Vec(mcs_Start, mcs_End);
        gp_Vec poToStart = gp_Vec(mcs_Start, point);
        // 计算投影参数 t
        double t = dirction.Dot(poToStart) / dirction.Dot(dirction);

        // 计算投影点 p
        gp_Pnt p = mcs_Start.XYZ() + (t * dirction).XYZ();
        return p;
}

void EleLine::ResetConSubPoints(CElementBase* parentEle)
{
        CElementBase::ResetConSubPoints(parentEle);
        int i = 0;
        GeomAdaptor_Curve myCurve = GetCurve();
        if (PointF.size() < 3 || myCurve.Curve().IsNull())
        {
                return;
        }
        else
        {
                double dmax = 0;
                double dmin = 0;
                for (gp_Pnt p : this->PointF)
                {
                        try
                        {
                                if(this->m_elementOffset.m_bIsOffseted)
                                        p = FuncBase::GetMatrixPoint(this, p);
                                gp_Pnt subPt = FindClosestPointOnCurve(myCurve, p);
                                gp_Pnt pcsSubPt = FuncBase::ConvertToV2(parentEle, subPt);
                                gp_Pnt pcsP = FuncBase::ConvertToV2(parentEle, p);
                                FuncBase::SetPcsPoint(parentEle, pcsSubPt, pcsP);
                                subPt = FuncBase::ConvertPcsToMcs(parentEle, pcsSubPt);
                                int index = MathHelper::returnRightOrLeft(mcs_Start, mcs_End, p);
                                double distance = subPt.Distance(p);
                                Distances.push_back(distance);
                                if (index == 2)
                                        distance = -distance;
                                this->ConSubPoints.push_back({ p ,subPt,distance, Quantity_Color(Quantity_NOC_WHEAT) });
                                gp_Vec realVec = gp_Vec(mcs_Start, p);
                                gp_Vec lineVec = gp_Vec(mcs_Start, mcs_End);
                                double s = (realVec.X() * lineVec.Y() - realVec.Y() * lineVec.X()) >= 0. ? 1 : -1;
                                distance = s * distance;

                                if (0 == i)
                                {
                                        dmax = dmin = distance;
                                }
                                i++;
                                if (distance > dmax)
                                        dmax = distance;
                                if (distance < dmin)
                                        dmin = distance;
                        }
                        catch (const std::exception& e)
                        {
                                std::ignore = e;
                                continue;

                        }

                }
                this->MaxOffset = to_string(dmax);
                this->MinOffset = to_string(dmin);
        }

        CElementBase::FiltFit();
}

/// <summary>
/// 执行构造
/// </summary>
/// <param name="selectEles"></param>
/// <param name="parentEle"></param>
/// <param name="elements"></param>
/// <param name="fullElements"></param>
/// <returns></returns>
bool  EleLine::ExecuteTools(vector<CElementBase*> selectEles,
        CElementBase* parentEle, bool isMulPoint, int fitMethod)
{

        bool ret = false;
        auto tempTooltype  = vecToolTypes;
        map<ToolType, bool>::iterator itAu;
        map<ToolType, bool>::iterator itmid;
        vector<gp_Pnt> myAddPts;
        std::list<ToolsInput>::iterator itav;
        for (auto it = tempTooltype.begin(); it != tempTooltype.end(); ++it)
        {
                auto uesedKeyValue = IsUesedToolTypes.find(*it);
                if (uesedKeyValue != IsUesedToolTypes.end()) //&& !uesedKeyValue->second
                {
                        auto mdIt = IsUesedToolTypes.find(MidPointComposition);
                        auto auIt = IsUesedToolTypes.find(AutomaticDecision);
                        auto bisIt = IsUesedToolTypes.find(Bisector);
                                
                        switch (*it)
                        {
                        case AutomaticDecision: //已改
                                //存在平分和自动判断时,平分已构造完成则不需要走自动判断
                                if (bisIt != IsUesedToolTypes.end() && IsUesedToolTypes[Bisector]) break;
                                if (selectEles.size() == 2 && (selectEles.at(0) == selectEles.at(1)))
                                {
                                        selectEles.pop_back();
                                }                                
                                ret = AutomaticLine(selectEles, parentEle, myAddPts, fitMethod);
                                if (mdIt != IsUesedToolTypes.end())
                                {
                                        for (auto tools : this->toolTypes[ToolType::MidPointComposition])        
                                        {
                                                itav = find_if(this->toolTypes[ToolType::AutomaticDecision].begin(), this->toolTypes[ToolType::AutomaticDecision].end(),
                                                        [tools](const ToolsInput tool) {
                                                                return tool.InputEleID._Equal(tools.InputEleID);
                                                        });
                                                // 查找特征

                                                // 如果找到了该特征
                                                if (itav != this->toolTypes[ToolType::AutomaticDecision].end())
                                                        this->toolTypes[ToolType::AutomaticDecision].erase(itav); // 移除特征

                                        }

                                }
                                
                                
                                break;
                        case Bisector:  //已改
                                ret = LineBisector(selectEles, parentEle);
                                break;
                        case Vertical:   //已改
                                if(!IsUesedToolTypes[Vertical])
                                ret = LineVertical(*(--selectEles.end()), parentEle);
                                break;
                        case Parallel:    //已改
                                if (!IsUesedToolTypes[Parallel])
                                ret = LineParalle(*(--selectEles.end()), parentEle);
                                break;
                        case MidPointComposition:  //已改
                                if (uesedKeyValue->second )
                                {
                                        if (selectEles.size() == 0)
                                                ret = true;
                                        string curUid = selectEles.at(0)->m_strElementUid;
                                        list<ToolsInput> listInput = toolTypes[*it];
                                        auto findit = find_if(listInput.begin(), listInput.end(),
                                                [curUid](const ToolsInput tool) {
                                                        return tool.InputEleID._Equal(curUid);
                                                });
                                        if (findit != listInput.end())
                                                break;
                                        else
                                        {
                                                ret = true;
                                        }                                
                                }
                                
                                ret = LineMidPointComposition(selectEles, parentEle);
                                if (auIt != IsUesedToolTypes.end())
                                {
                                        for (auto tools : this->toolTypes[ToolType::AutomaticDecision])
                                        {

                                                itav = find_if(this->toolTypes[ToolType::MidPointComposition].begin(), this->toolTypes[ToolType::MidPointComposition].end(),
                                                        [tools](const ToolsInput tool) {
                                                                return tool.InputEleID._Equal(tools.InputEleID);
                                                        });
                                                // 查找特征

                                                // 如果找到了该特征
                                                if (itav != this->toolTypes[ToolType::MidPointComposition].end())
                                                        this->toolTypes[ToolType::MidPointComposition].erase(itav); // 移除特征
                                        }
                                }                                                        
                                break;
                        case Cross:
                                ret = LineCorss(selectEles, parentEle);  //不需要改动 工作平面
                                break;
                        case TangentLine:
                                ret = LineTange(selectEles, parentEle);  //已改
                                break;
                        case MinimumRange:
                                ret = LineMinimunRange(selectEles, parentEle);
                                break;
                        case ToolType::callOut:
                                ret = CallOutLine(selectEles[0], parentEle); break;
                        default: break;
                        }

                }
                if (uesedKeyValue == IsUesedToolTypes.end()) continue;
                auto it1 = IsUesedToolTypes.find(uesedKeyValue->first);
                if (!mcs_Start.IsEqual(mcs_End, 1e-6) && !mcs_Start.IsEqual(gp_Pnt(0, 0, 0), 1e-6) && !mcs_End.IsEqual(gp_Pnt(0, 0, 0), 1e-6)
                        && (it1 == IsUesedToolTypes.end() || !it1->second))
                        this->IsUesedToolTypes[uesedKeyValue->first] = true;
        }
        ResetConSubPoints(parentEle);
        return ret;
}

bool EleLine::FiltFitShape(vector<gp_Pnt>& contourPos, int& removeCount)
{
        bool ret = CElementBase::FiltFitShape(contourPos, removeCount);
        if (!ret)
                return false;

    ret = FitLine(contourPos, this->parentCoordnate, this->mcs_Start, this->mcs_End, 0);

        if (ret)
        {
                Distances.clear();
                double dmax = 0;
                double dmin = 0;
                int i = 0;
                GeomAdaptor_Curve myCurve = GetCurve();
                if (myCurve.Curve().IsNull())
                {
                        return ret;
                }
                for (auto& myPairs : this->ConSubPoints)
                {
                        try
                        {
                                gp_Pnt pt = get<0>(myPairs);
                                gp_Pnt subPt = FindClosestPointOnCurve(myCurve, pt);
                                gp_Pnt pcsSubPt = FuncBase::ConvertToV2(parentCoordnate, subPt);
                                gp_Pnt pcsP = FuncBase::ConvertToV2(parentCoordnate, pt);
                                FuncBase::SetPcsPoint(parentCoordnate, pcsSubPt, pcsP);
                                subPt = FuncBase::ConvertPcsToMcs(parentCoordnate, pcsSubPt);
                                int index = MathHelper::returnRightOrLeft(mcs_Start, mcs_End, pt);
                                double distance = subPt.Distance(pt);
                                Distances.push_back(distance);
                                if (index == 2)
                                        distance = -distance;
                                myPairs = std::make_tuple(pt, subPt, distance, get<3>(myPairs));

                                gp_Vec realVec = gp_Vec(mcs_Start, pt);
                                gp_Vec lineVec = gp_Vec(mcs_Start, mcs_End);
                                double s = (realVec.X() * lineVec.Y() - realVec.Y() * lineVec.X()) >= 0. ? 1 : -1;
                                distance = s * distance;
                                if (0 == i)
                                {
                                        dmax = dmin = distance;
                                }
                                i++;
                                if (distance > dmax)
                                        dmax = distance;
                                if (distance < dmin)
                                        dmin = distance;
                        }
                        catch (const std::exception& e)
                        {
                                std::ignore = e;
                                continue;
                        }
                        
                }
                this->MaxOffset = to_string(dmax);
                this->MinOffset = to_string(dmin);
                CElementBase::FiltFitShape(contourPos, removeCount);  //最后再排除下过滤点
        }
        return ret;
}

/// <summary>
/// 特征判断
/// </summary>
/// <param name="elementType"></param>
/// <param name="toolType"></param>
/// <returns></returns>
bool EleLine::EleJudge(ElementType elementType, ToolType toolType)
{
        switch (toolType)
        {
        case ToolType::AutomaticDecision:
                return true;
        case ToolType::PointsInput:
                return true;
        case ToolType::MidPointComposition:
                switch (elementType)
                {
                case ELE_PLANE: return false;
                case ELE_OPEN_CLOUD_LINE: return false;
                case ELE_POINT_CLOUD: return false;
                default: return true;
                }
        case ToolType::Cross:
                switch (elementType)
                {
                case ELE_PLANE: return true;
                default: return false;
                }
        case ToolType::Bisector:
                switch (elementType)
                {
                case ELE_PLANE: return false;
                case ELE_OPEN_CLOUD_LINE: return false;
                case ELE_POINT_CLOUD: return false;
                default: return true;
                }
        case ToolType::Vertical:
                switch (elementType)
                {
                case ELE_LINE: return true;
                case ELE_ELLIPSE: return true;
                case ELE_GAP: return true;
                case ELE_DISTANCE: return true;
                case ELE_RECTANGLE: return true;
                default: return false;
                }
        case ToolType::Parallel:
                switch (elementType)
                {
                case ELE_LINE: return true;
                case ELE_RECTANGLE: return true;
                case ElE_COORDINATION_SYSTME: return true;
                case ELE_GAP: return true;
                case ELE_DISTANCE: return true;
                default: return false;
                }
        case ToolType::TangentLine:
                switch (elementType)
                {
                case ELE_CIRCLE: return true;
                case ELE_ARC: return true;
                case ELE_ELLIPSE: return true;
                default: return false;
                }
        case ToolType::MinimumRange:
                switch (elementType)
                {
                case ELE_POINT: return true;
                case ELE_LINE: return true;
                case ELE_OPEN_CLOUD_LINE: return true;
                default: return false;
                }
        default: return false;
        }
}

/// <summary>
/// 自动判断
/// </summary>
/// <param name="selectEles"></param>
/// <param name="parentEle"></param>
/// <returns></returns>
bool EleLine::AutomaticLine(vector<CElementBase*> selectEles, CElementBase* parentEle,vector<gp_Pnt> addPoints,int fitMethod)
{
        list<ToolsInput> toolsInputs = list<ToolsInput>();
        try
        {
                if (selectEles.at(0))
                        this->PointF.clear();
                this->ParentUid = parentEle->m_strElementUid;
                Alignment* myCoord = ((Alignment*)parentEle);
                gp_Pln myPlane = FuncBase::GetWorkingPlane(parentEle);
                gp_Pnt mcsPt;
                vector< int> myCloudLineIndexs;
                for (int i = 0; i < selectEles.size(); i++)
                {
                        if (this->m_listComponentElements.size() > 0)
                        {
                                ComponentEle* mySegement = nullptr;
                                selectEles->PointF.clear();
                                for (auto comPonent : this->m_listComponentElements)
                                {
                                        if (comPonent->IsSegementCom)
                                                mySegement = comPonent;
                                        if (mySegement != nullptr && selectEles->m_strElementUid == mySegement->m_strComponentUid)
                                        {
                                                vector<gp_Pnt> mySePts = ((EleOpenCloudLine*)selectEles)->ExtractSegmentFromCloudPoints(mySegement->SegementPts.at(0), mySegement->SegementPts.at(1), mySegement->IsOtherEdge);
                                                
                                                selectEles->PointF.insert(selectEles->PointF.end(), mySePts.begin(),
                                                        mySePts.end());
                                                
                                        }
                                        else
                                        {
                                                continue;
                                        }
                                }
                                
                        }
                        
                }
                if (selectEles.size() == 1 && (selectEles.at(0)->nType == ELE_LINE || selectEles.at(0)->nType == ELE_POINT || selectEles.at(0)->nType == ElE_COORDINATION_SYSTME || selectEles.at(0)->nType == ELE_POINT_CLOUD))
                {
                        if (!vec_Line.IsEqual(gp_Vec(0, 0, 0), 1.0e-9, 1.0e-9))
                        {
                                string toolName = ToolTypeToString(ToolType::PointsInput);
                                
                                if (selectEles.at(0)->nType == ELE_LINE)
                                {
                                        this->Length = ((EleLine*)selectEles.at(0))->Length;
                                        this->PointF.insert(this->PointF.end(), selectEles.at(0)->PointF.begin(), selectEles.at(0)->PointF.end());
                                }               
                                else
                                {
                                        toolName = ToolTypeToString(ToolType::MidPointComposition);
                                }
                                gp_Dir normal = myPlane.Axis().Direction();

                                // 2. 计算向量在法向量方向上的分量(点积 * 法向量)
                                double dot = vec_Line.Dot(normal);
                                gp_Vec normalComponent = normal.XYZ() * dot;

                                // 3. 减去垂直分量,得到平面上的投影
                                gp_Vec projectedVec = vec_Line - normalComponent;
                                projectedVec.Normalize();
                                this->m_pMCS->McsPosition = selectEles.at(0)->GetMcsPosition();
                                this->mcs_Start = this->m_pMCS->McsPosition.XYZ() + (projectedVec * this->Length * 0.5f).XYZ();
                                this->mcs_End = this->m_pMCS->McsPosition.XYZ() - (projectedVec * this->Length * 0.5f).XYZ();
                                this->vec_Line = gp_Vec(0, 0, 0);
                                this->PointF.push_back(mcs_Start);
                                this->PointF.push_back(mcs_End);
                                toolsInputs.push_back(ToolsInput{ toolName, selectEles.at(0)->m_strElementName,selectEles.at(0)->m_strElementUid });
                        }
                        else
                        {
                          bool retemp =        LinePointsInput(selectEles, parentEle, toolsInputs, addPoints, AutomaticDecision, fitMethod);
                          if (!retemp)
                          {
                                  exception ex;
                                  throw ex;
                          }
                        }
                }
                else if((selectEles.size() == 2) && (selectEles.at(0)->nType != ELE_LINE || selectEles.at(1)->nType != ELE_LINE))
                {
                        if (toolTypes[ToolType::AutomaticDecision].size() > 0)
                        {
                                string tName = toolTypes[ToolType::AutomaticDecision].begin()->ToolName;
                                if (tName.find(ToolTypeToString(ToolType::TangentLine)) != std::string::npos)
                                {
                                        vector<CElementBase*> solutions;
                                        //圆圆切线
                                        if (selectEles.at(1)->nType == ELE_CIRCLE || selectEles.at(1)->nType == ELE_ARC)
                                        {
                                                toolsInputs.push_back(ToolsInput{ ToolTypeToString(ToolType::TangentLine), selectEles.at(0)->m_strElementName, selectEles.at(0)->m_strElementUid });
                                                toolsInputs.push_back(ToolsInput{ ToolTypeToString(ToolType::TangentLine), selectEles.at(1)->m_strElementName, selectEles.at(1)->m_strElementUid });
                                                solutions = PointCircleTangenLine(this, selectEles.at(0), selectEles.at(1)->GetMcsPosition(), selectEles, parentEle, true);
                                        }
                                        else//点圆切线
                                        {
                                                toolsInputs.push_back(ToolsInput{ ToolTypeToString(ToolType::TangentLine), selectEles.at(0)->m_strElementName, selectEles.at(0)->m_strElementUid });
                                                toolsInputs.push_back(ToolsInput{ ToolTypeToString(ToolType::MidPointComposition), selectEles.at(1)->m_strElementName, selectEles.at(1)->m_strElementUid });
                                                solutions = PointCircleTangenLine(this, selectEles.at(0), selectEles.at(1)->GetMcsPosition(), selectEles, parentEle, false);
                                        }
                                        //后续返回线段(用特征得id代表)
                                        if (mySolutCallback && m_nSolutionIndex == -1)
                                                mySolutCallback(solutions);
                                        else
                                        {
                                                EleLine* ele_Line = (EleLine*)solutions.at(m_nSolutionIndex);
                                                this->mcs_Start = ele_Line->mcs_Start;
                                                this->mcs_End = ele_Line->mcs_End;
                                                this->Length = ele_Line->Length;
                                                this->m_pMCS->McsPosition = ele_Line->m_pMCS->McsPosition;
                                                this->m_pPCS->PcsPosition = ele_Line->m_pPCS->PcsPosition;
                                                this->m_elementOffset.BefMcsPoint = ele_Line->m_elementOffset.BefMcsPoint;
                                        }                                       
                                    this->toolTypes[ToolType::TangentLine] = toolsInputs;
                                    this->IsUesedToolTypes[TangentLine] = true;
                                        return true;
                                }
                        }
                        toolsInputs.push_back(ToolsInput{ ToolTypeToString(ToolType::MidPointComposition), selectEles.at(0)->m_strElementName, selectEles.at(0)->m_strElementUid });
                        string toolName = ToolTypeToString(ToolType::MidPointComposition);
                        PointF.clear();
                        PointF.push_back(selectEles.at(0)->GetMcsPosition());
                        vector<gp_Pnt> listPoints = PointF;
                        tuple<gp_Pnt, gp_Pnt> vectors = make_tuple(gp_Pnt(), gp_Pnt());
                        switch (selectEles.at(1)->nType)
                        {
                        case ELE_LINE:
                                toolName = ToolTypeToString(ToolType::PointsInput);
                                PointF.insert(PointF.end(), selectEles.at(1)->PointF.begin(), selectEles.at(1)->PointF.end());
                                //使用最小二乘法确定线段的起点和终点
                                vectors = MathHelper::GetFitLine(listPoints);
                                mcs_Start = get<0>(vectors);
                                mcs_End = get<1>(vectors);
                                break;
                        default:
                                mcs_Start = selectEles.at(0)->GetMcsPosition();
                                mcs_End = selectEles.at(1)->GetMcsPosition();
                                PointF.push_back(selectEles.at(1)->GetMcsPosition());
                                break;
                        }

                        mcsPt = (mcs_Start.XYZ() + mcs_End.XYZ()) * 0.5;
                        mcs_Start = MathHelper::FindClosestPointOnPlane(myPlane,mcs_Start);
                        mcs_End = MathHelper::FindClosestPointOnPlane(myPlane, mcs_End);
                        gp_Pnt pcs_pt = FuncBase::ConvertToV2(myCoord, mcsPt);
                        mcs_Start = FuncBase::ConvertToV2(myCoord, mcs_Start);
                        mcs_End = FuncBase::ConvertToV2(myCoord, mcs_End);


                        switch (myCoord->workingPlaneIdx)
                        {
                        case 0:
                                mcs_Start.SetZ(pcs_pt.Z());
                                mcs_End.SetZ(pcs_pt.Z());
                                break;
                        case 1:
                                mcs_Start.SetX(pcs_pt.X());
                                mcs_End.SetX(pcs_pt.X());
                                break;
                        case 2:
                                mcs_Start.SetY(pcs_pt.Y());
                                mcs_End.SetY(pcs_pt.Y());
                                break;
                        default:
                                break;
                        }
                        mcs_Start = FuncBase::ConvertPcsToMcs(myCoord, mcs_Start);
                        mcs_End = FuncBase::ConvertPcsToMcs(myCoord, mcs_End);

                        toolsInputs.push_back(ToolsInput{ toolName,selectEles.at(1)->m_strElementName,  selectEles.at(1)->m_strElementUid });
                        m_pMCS->McsPosition = (mcs_Start.XYZ() + mcs_End.XYZ()) * 0.5f;
                        toolTypes[ToolType::AutomaticDecision] = toolsInputs;
                        IsUesedToolTypes[AutomaticDecision] = true;
                }
                else
                {
                        bool retemp = LinePointsInput(selectEles, parentEle, toolsInputs, addPoints, AutomaticDecision, fitMethod);
                        if (!retemp)
                        {
                                exception ex;
                                throw ex;
                        }
                }
                if (myCloudLineIndexs.size() > 0)
                {
                        for (int i = 0; i < myCloudLineIndexs.size(); i++)
                        {
                                selectEles->PointF.clear();  //清除云线的点集合
                        }
                }
                double dis = mcs_Start.Distance(mcs_End);
                double length = dis;
                if(selectEles.size() == 1)
                         length = (selectEles.at(0)->nType == ELE_LINE) ? ((EleLine*)selectEles.at(0))->Length : dis;
                this->Length = length;
                m_pMCS->McsPosition = (mcs_Start.XYZ() + mcs_End.XYZ()) * 0.5;
                unordered_set<string> seen;
                std::list<ToolsInput> deduped;
                for (const auto& item : toolsInputs)
                {
                        if (seen.insert(item.InputEleID).second) {
                                deduped.push_back(item);
                        }
                }

                toolsInputs.swap(deduped);  // 替换回原 list
                this->toolTypes[ToolType::AutomaticDecision] = toolsInputs;
                this->IsUesedToolTypes[AutomaticDecision] = true;
                return true;
        }
        catch (const std::exception& ex)
        {
                std::cerr << "Exception caught: " << ex.what() << std::endl;
                toolTypes[ToolType::AutomaticDecision] = toolsInputs;
                IsUesedToolTypes[AutomaticDecision] = false;
                return false;
        }
}

/// <summary>
/// 垂直
/// </summary>
/// <param name="selectEle"></param>
/// <param name="parentEle"></param>
/// <returns></returns>
bool EleLine::LineVertical(CElementBase* selectEle, CElementBase* parentEle)
{
        list<ToolsInput> toolsInputs = list<ToolsInput>();
        try
        {
                gp_Vec vec;
                EleLine* line = nullptr;
                toolsInputs.push_back(ToolsInput{ ToolTypeToString(ToolType::Vertical),selectEle->m_strElementName, selectEle->m_strElementUid });
                Alignment* myCoord = ((Alignment*)parentEle);
                gp_Pln myPlane = FuncBase::GetWorkingPlane(parentEle);
                gp_Pnt mcsPt;
                switch (selectEle->nType)
                {
                case ELE_GAP:
                {
                        EleGap* gapline = (EleGap*)selectEle;
                        line = gapline->lineSegment1;
                }
                case ELE_DISTANCE:
                case ELE_LINE:
                {
                        if (line == nullptr)
                                line = (EleLine*)selectEle;
                        auto start_end = line->GetLineMcsStartEndPoint();
                        gp_Pnt mcs_Start = get<0>(start_end);
                        gp_Pnt mcs_End = get<1>(start_end);
                        this->Length = mcs_Start.Distance(mcs_End);
                        mcs_Start = MathHelper::FindClosestPointOnPlane(myPlane, mcs_Start);
                        mcs_End = MathHelper::FindClosestPointOnPlane(myPlane, mcs_End);
                        vec = gp_Vec(mcs_Start, mcs_End);
                        break;
                }
                case ElE_COORDINATION_SYSTME:
                {
                        Alignment* sysCoord = (Alignment*)selectEle;
                        auto myVec = sysCoord->GetWPVec();
                        vec = std::get<0>(myVec);
                        this->Length = 10;
                        break;
                }
                default:
                        break;
                }
                vec = gp_Vec(-vec.Y(), vec.X(), vec.Z());
                vec_Line = vec;
                if (!this->m_pMCS->McsPosition.IsEqual(gp_Pnt(0, 0, 0), 1.0e-9))
                {
                        this->mcs_Start = this->m_pMCS->McsPosition.XYZ() + (vec_Line * this->Length * 0.5f).XYZ();
                        this->mcs_End = this->m_pMCS->McsPosition.XYZ() - (vec_Line * this->Length * 0.5f).XYZ();
                        this->vec_Line = gp_Vec(0, 0, 0);
                }
                this->ParentUid = parentEle->m_strElementUid;
                this->toolTypes[ToolType::Vertical] = toolsInputs;
                this->IsUesedToolTypes[Vertical] = true;
                return true;
        }
        catch (const std::exception& e)
        {
                std::ignore = e;
                this->toolTypes[ToolType::Vertical] = toolsInputs;
                this->IsUesedToolTypes[Vertical] = false;
                return false;
        }
}

/// <summary>
/// 平行
/// </summary>
/// <param name="selectEle"></param>
/// <param name="parentEle"></param>
/// <returns></returns>
bool EleLine::LineParalle(CElementBase* selectEle, CElementBase* parentEle)
{
        list<ToolsInput> toolsInputs = list<ToolsInput>();
        try
        {
                gp_Vec vec;
                toolsInputs.push_back(ToolsInput{ ToolTypeToString(ToolType::Parallel),selectEle->m_strElementName, selectEle->m_strElementUid });
                EleLine* line = nullptr;
                Alignment* myCoord = ((Alignment*)parentEle);
                gp_Pln myPlane = FuncBase::GetWorkingPlane(parentEle);
                gp_Pnt mcsPt;
                switch (selectEle->nType)
                {
                case ELE_GAP:
                {
                        EleGap* gapline = (EleGap*)selectEle;
                        line = gapline->lineSegment1;
                }
                case ELE_DISTANCE:
                case ELE_LINE:
                {
                        if (line == nullptr)
                                line = (EleLine*)selectEle;
                        auto start_end = line->GetLineMcsStartEndPoint();
                        gp_Pnt mcs_Start = get<0>(start_end);
                        gp_Pnt mcs_End = get<1>(start_end);
                        this->Length = mcs_Start.Distance(mcs_End);
                        mcs_Start = MathHelper::FindClosestPointOnPlane(myPlane, mcs_Start);
                        mcs_End = MathHelper::FindClosestPointOnPlane(myPlane, mcs_End);
                        vec = gp_Vec(mcs_Start, mcs_End);
                        
                        break;
                }        
                case ElE_COORDINATION_SYSTME:
                {
                        Alignment* sysCoord = (Alignment*)selectEle;
                        auto myVec = sysCoord->GetWPVec();
                        vec = std::get<0>(myVec);
                        this->Length = 10;
                        break;
                }        
                default:
                        break;
                }
               
                vec.Normalize();
                vec_Line = vec;
                if (!this->m_pMCS->McsPosition.IsEqual(gp_Pnt(0, 0, 0), 1.0e-9))
                {
                        this->mcs_Start = this->m_pMCS->McsPosition.XYZ() + (vec_Line * this->Length * 0.5f).XYZ();
                        this->mcs_End = this->m_pMCS->McsPosition.XYZ() - (vec_Line * this->Length * 0.5f).XYZ();
                        this->vec_Line = gp_Vec(0, 0, 0);
                }
                this->ParentUid = parentEle->m_strElementUid;
                this->toolTypes[ToolType::Parallel] = toolsInputs;
                this->IsUesedToolTypes[Parallel] = true;
                return true;
        }
        catch (const std::exception& ex)
        {
                std::cerr << "Exception caught: " << ex.what() << std::endl;
                this->toolTypes[ToolType::Parallel] = toolsInputs;
                this->IsUesedToolTypes[Parallel] = false;
                return false;
        }
}

/// <summary>
/// 切线
/// </summary>
/// <param name="selectEles"></param>
/// <param name="parentEle"></param>
/// <returns></returns>
bool EleLine::LineTange(vector<CElementBase*> selectEles, CElementBase* parentEle)
{
        list<ToolsInput> toolsInputs = list<ToolsInput>();
        try
        {
                toolsInputs.push_back(ToolsInput{ ToolTypeToString(ToolType::TangentLine), selectEles.at(0)->m_strElementName, selectEles.at(0)->m_strElementUid });
                toolsInputs.push_back(ToolsInput{ ToolTypeToString(ToolType::TangentLine), selectEles.at(1)->m_strElementName, selectEles.at(1)->m_strElementUid });
                bool isAllCircle = false;
                if ((selectEles.at(0)->nType == ELE_CIRCLE && selectEles.at(1)->nType == ELE_CIRCLE) || (selectEles.at(0)->nType == ELE_ARC && selectEles.at(1)->nType == ELE_ARC))
                        isAllCircle = true;
                //点圆切线
                auto solutions = PointCircleTangenLine(this, selectEles.at(1), selectEles.at(0)->GetMcsPosition(), selectEles, parentEle, isAllCircle);
               
                if (mySolutCallback && m_nSolutionIndex == -1)
                        mySolutCallback(solutions);
                else
                {
                        EleLine* ele_Line = (EleLine*)solutions.at(m_nSolutionIndex);
                        this->mcs_Start = ele_Line->mcs_Start;
                        this->mcs_End = ele_Line->mcs_End;
                        this->Length = ele_Line->Length;
                        this->m_pMCS->McsPosition = ele_Line->m_pMCS->McsPosition;
                        this->m_pPCS->PcsPosition = ele_Line->m_pPCS->PcsPosition;
                        this->m_elementOffset.BefMcsPoint = ele_Line->m_elementOffset.BefMcsPoint;
                }
                this->toolTypes[ToolType::TangentLine] = toolsInputs;
                this->IsUesedToolTypes[TangentLine] = true;
                return true;
        }
        catch (const std::exception& ex)
        {
                std::cerr << "Exception caught: " << ex.what() << std::endl;
                this->toolTypes[ToolType::TangentLine] = toolsInputs;
                this->IsUesedToolTypes[TangentLine] = false;
                return false;
        }
}

/// <summary>
/// 多点输入
/// </summary>
/// <param name="selectEles"></param>
/// <param name="parentEle"></param>
/// <returns></returns>
bool EleLine::LinePointsInput(vector<CElementBase*> selectEles, CElementBase* parentEle, list<ToolsInput>& toolsInputs, vector<gp_Pnt> addPoints, ToolType myType, int fitMethod)
{
        try
        {
                this->PointF.clear();
                vector< int> myCloudLineIndexs;
                unordered_set<string> seen;
                std::list<ToolsInput> deduped;
                for (int i = 0; i < selectEles.size(); i++)
                {
                        if (selectEles->nType == ELE_LINE || selectEles->nType == ELE_POINT_CLOUD || selectEles->nType ==ELE_OPEN_CLOUD_LINE|| selectEles->nType == ELE_CLOSE_CLOUD_LINE)
                        {
                                ToolsInput toolsInput = ToolsInput();
                                if (this->m_listComponentElements.size() > 0  && selectEles->nType != ELE_LINE)
                                {
                                        ComponentEle* mySegement = nullptr;
                                        selectEles->PointF.clear();
                                        for  (auto  comPonent : this->m_listComponentElements)
                                        {
                                                if (comPonent->IsSegementCom)
                                                        mySegement = comPonent;
                                                if (mySegement != nullptr && selectEles->m_strElementUid == mySegement->m_strComponentUid)
                                                {
                                                        vector<gp_Pnt> mySePts = ((EleOpenCloudLine*)selectEles)->ExtractSegmentFromCloudPoints(mySegement->SegementPts.at(0), mySegement->SegementPts.at(1), mySegement->IsOtherEdge);

                                                        selectEles->PointF.insert(selectEles->PointF.end(), mySePts.begin(),
                                                                mySePts.end());
                                                }
                                                else
                                                {
                                                        continue;
                                                }
                                        }               
                                        myCloudLineIndexs.push_back(i);
                                        toolsInput.ToolName = ToolTypeToString(ToolType::SectionComposition);
                                }
                        else
                        {
                                toolsInput.ToolName = ToolTypeToString(ToolType::PointsInput);
                        }
                        
                        toolsInput.InputEleName = selectEles->m_strElementName;
                                toolsInput.InputEleID = selectEles->m_strElementUid;
                                toolsInputs.push_back(toolsInput);
                                this->PointF.insert(this->PointF.end(), selectEles->PointF.begin(), selectEles->PointF.end());
                        }
                        else
                        {                                
                                ToolsInput toolsInput = ToolsInput();
                                toolsInput.ToolName = ToolTypeToString(ToolType::MidPointComposition);
                                toolsInput.InputEleName = selectEles->m_strElementName;
                                toolsInput.InputEleID = selectEles->m_strElementUid;
                                toolsInputs.push_back(toolsInput);
                                this->PointF.push_back(selectEles->GetMcsPosition());
                        }
                }

                this->PointF.insert(this->PointF.end(), addPoints.begin(), addPoints.end());
                bool fitRet = FitLine(this->PointF, parentEle, this->mcs_Start, this->mcs_End, fitMethod);
                if (fitRet && selectEles.size() > 0 && selectEles[0] != nullptr)
                {
                        LogEleLinePointsInputFitIfSet(
                                selectEles[0]->m_strElementUid.c_str(),
                                (int)this->PointF.size(),
                                this->mcs_Start.X(), this->mcs_Start.Y(), this->mcs_Start.Z(),
                                this->mcs_End.X(), this->mcs_End.Y(), this->mcs_End.Z());
                }
                if (!fitRet)
                {
                        for (const auto& item : toolsInputs)
                        {
                                if (seen.insert(item.InputEleID).second) {
                                        deduped.push_back(item);
                                }
                        }

                        toolsInputs.swap(deduped);  // 替换回原 list
                        this->toolTypes[myType] = toolsInputs;
                        this->IsUesedToolTypes[myType] = false;
                        return false;
                }        
                if (myCloudLineIndexs.size() > 0)
                {
                        for (int i = 0; i < myCloudLineIndexs.size(); i++)
                        {
                                selectEles->PointF.clear();  //清除云线的点集合
                        }
                }
                this->m_pMCS->McsPosition = (this->mcs_Start.XYZ() + this->mcs_End.XYZ()) * 0.5;
                this->ParentUid = parentEle->m_strElementUid;
                return true;
        }
        catch (const std::exception& ex)
        {
                std::cerr << "Exception caught: " << ex.what() << std::endl;
                this->toolTypes[myType] = toolsInputs;
                this->IsUesedToolTypes[myType] = false;
                return false;
        }

}

bool EleLine::FitLine(vector<gp_Pnt> fitPoints, CElementBase* parentEle, gp_Pnt& startPt, gp_Pnt& endPt, int fitMethod)
{
        if (fitPoints.size() < 2)
        {
                return false;
        }
        gp_Pln myPlane = FuncBase::GetWorkingPlane(parentEle);
        Alignment* myCoord = ((Alignment*)parentEle);
        gp_Pnt mcsPt;
        vector<gp_Pnt> fitPts;
        for (int i = 0; i < fitPoints.size(); i++)
        {
                mcsPt = mcsPt.XYZ() + fitPoints.XYZ();
                gp_Pnt subPoint = MathHelper::FindClosestPointOnPlane(myPlane, fitPoints);
                fitPts.push_back(subPoint);
        }
        mcsPt = mcsPt.XYZ() / static_cast<Standard_Real>(fitPoints.size());

        // 端点与扫描一致:cv::fitLine + 拾取框 Line2Lseg,不用 GetFitLine 坐标轴极值
        double height = GetCurPixelLength();
        tuple<gp_Pnt, gp_Pnt> pairs = MathHelper::GetFitLineEndpoints_LS(fitPts, myCoord->workingPlaneIdx);
        startPt= std::get<0>(pairs);
        endPt = std::get<1>(pairs);

        gp_Pnt pcs_Start = FuncBase::ConvertToV2(myCoord, startPt);
        gp_Pnt pcs_End = FuncBase::ConvertToV2(myCoord, endPt);
        gp_Pnt pcs_pt = FuncBase::ConvertToV2(myCoord, mcsPt);

        switch (myCoord->workingPlaneIdx)
        {
        case 0:
                pcs_Start.SetZ(pcs_pt.Z());
                pcs_End.SetZ(pcs_pt.Z());
                break;
        case 1:
                pcs_Start.SetX(pcs_pt.X());
                pcs_End.SetX(pcs_pt.X());
                break;
        case 2:
                pcs_Start.SetY(pcs_pt.Y());
                pcs_End.SetY(pcs_pt.Y());
                break;
        default:
                break;
        }
        startPt= FuncBase::ConvertPcsToMcs(myCoord, pcs_Start);
        endPt = FuncBase::ConvertPcsToMcs(myCoord, pcs_End);

        auto lastPt = fitPoints.at(0);
        double startDis = lastPt.Distance(startPt);
        double lastDis = lastPt.Distance(endPt);
        if (startDis > lastDis)
        {
                gp_Pnt tempPt = startPt;
                startPt= endPt;
                endPt = tempPt;
        }
        return true;
}

/// <summary>
/// 中点构成
/// </summary>
/// <param name="selectEles"></param>
/// <param name="parentEle"></param>
/// <returns></returns>
bool EleLine::LineMidPointComposition(vector<CElementBase*> selectEles, CElementBase* parentEle)
{
        try
        {
                list<ToolsInput> toolsInputs = list<ToolsInput>();
                this->PointF.clear();
                if (selectEles.size() == 1)
                {
                        this->m_pMCS->McsPosition = selectEles.at(0)->GetMcsPosition();
                        toolsInputs.push_back(ToolsInput{ ToolTypeToString(ToolType::MidPointComposition), selectEles.at(0)->m_strElementName,selectEles.at(0)->m_strElementUid,vector<gp_Pnt> { selectEles.at(0)->GetMcsPosition() } });
                        this->PointF.push_back(selectEles.at(0)->GetMcsPosition());
                        this->toolTypes[ToolType::MidPointComposition] = toolsInputs;
                        if (!vec_Line.IsEqual(gp_Vec(0, 0, 0), 1.0e-9, 1.0e-9))
                        {
                                this->mcs_Start = this->m_pMCS->McsPosition.XYZ() + (vec_Line * this->Length * 0.5f).XYZ();
                                this->mcs_End = this->m_pMCS->McsPosition.XYZ() - (vec_Line * this->Length * 0.5f).XYZ();
                                this->vec_Line = gp_Vec(0, 0, 0);
                                this->IsUesedToolTypes[MidPointComposition] = true;
                        }
                        else
                        {
                                this->IsUesedToolTypes[MidPointComposition] = false;
                                return false;
                        }
                }
                else if(selectEles.size() == 2)
                {
                        CElementBase* element1 = selectEles.at(0);
                        toolsInputs.push_back(ToolsInput{ ToolTypeToString(ToolType::MidPointComposition) ,element1->m_strElementName ,element1->m_strElementUid ,vector<gp_Pnt> { element1->GetMcsPosition() } });
                        CElementBase* element2 = selectEles.at(1);
                        //检查是否有垂直/平行构造
                        if (element2->nType == ELE_LINE || element2->nType == ELE_DISTANCE || element2->nType == ELE_GAP || element2->nType == ElE_COORDINATION_SYSTME)
                        {
                                auto verIt = IsUesedToolTypes.find(Vertical);
                                auto parIt = IsUesedToolTypes.find(Parallel);
                                if (verIt != IsUesedToolTypes.end())
                                        return LineVertical(element2, parentEle);
                                else if (parIt != IsUesedToolTypes.end())
                                        return LineParalle(element2, parentEle);
                        }
                        this->mcs_Start = element1->GetMcsPosition();
                        this->mcs_End = element2->GetMcsPosition();
                        auto lastEle = selectEles.at(selectEles.size() - 1);
                        gp_Pnt lastPt = lastEle->PointF.at(lastEle->PointF.size() - 1);
                        double startDis = lastPt.Distance(this->mcs_Start);
                        double lastDis = lastPt.Distance(this->mcs_End);
                        if (startDis < lastDis)
                        {
                                gp_Pnt tempPt = this->mcs_Start;
                                this->mcs_Start = this->mcs_End;
                                this->mcs_End = tempPt;
                        }
                        Alignment* myCoord = ((Alignment*)parentEle);
                        gp_Pln myPlane = FuncBase::GetWorkingPlane(parentEle);
                        gp_Pnt mcsPt;
                        mcsPt = (mcs_Start.XYZ() + mcs_End.XYZ()) * 0.5;
                        mcs_Start = MathHelper::FindClosestPointOnPlane(myPlane, mcs_Start);
                        mcs_End = MathHelper::FindClosestPointOnPlane(myPlane, mcs_End);
                        gp_Pnt pcs_pt = FuncBase::ConvertToV2(myCoord, mcsPt);
                        mcs_Start = FuncBase::ConvertToV2(myCoord, mcs_Start);
                        mcs_End = FuncBase::ConvertToV2(myCoord, mcs_End);


                        switch (myCoord->workingPlaneIdx)
                        {
                        case 0:
                                mcs_Start.SetZ(pcs_pt.Z());
                                mcs_End.SetZ(pcs_pt.Z());
                                break;
                        case 1:
                                mcs_Start.SetX(pcs_pt.X());
                                mcs_End.SetX(pcs_pt.X());
                                break;
                        case 2:
                                mcs_Start.SetY(pcs_pt.Y());
                                mcs_End.SetY(pcs_pt.Y());
                                break;
                        default:
                                break;
                        }
                        mcs_Start = FuncBase::ConvertPcsToMcs(myCoord, mcs_Start);
                        mcs_End = FuncBase::ConvertPcsToMcs(myCoord, mcs_End);

                        this->m_pMCS->McsPosition = (this->mcs_Start.XYZ() + this->mcs_End.XYZ()) * 0.5f;
                        this->Length = this->mcs_Start.Distance(this->mcs_End);
                        
                        toolsInputs.push_back(ToolsInput{ ToolTypeToString(ToolType::MidPointComposition) ,element2->m_strElementName ,element2->m_strElementUid ,vector<gp_Pnt> { element1->GetMcsPosition() } });
               
                        PointF.push_back(element1->m_pMCS->McsPosition);
                        PointF.push_back(element2->m_pMCS->McsPosition);
                        this->IsUesedToolTypes[MidPointComposition] = true;
                }
                else
                {                        
                         LinePointsInput(selectEles, parentEle, toolsInputs, vector<gp_Pnt> {}, MidPointComposition, 0);
                }
                this->toolTypes[ToolType::MidPointComposition] = toolsInputs;
                this->IsUesedToolTypes[MidPointComposition] = true;
                return true;
        }
        catch (const std::exception& ex)
        {
                std::cerr << "Exception caught: " << ex.what() << std::endl;
                this->IsUesedToolTypes[MidPointComposition] = false;
                this->m_elementOffset.BefMcsPoint = this->m_pMCS->McsPosition;
                return false;
        }
}

/// <summary>
/// 交叉
/// </summary>
/// <param name="selectEles"></param>
/// <param name="parentEle"></param>
/// <returns></returns>
bool EleLine::LineCorss(vector<CElementBase*> selectEles, CElementBase* parentEle)
{
        list<ToolsInput> toolsInputs = list<ToolsInput>();
        try
        {
                ToolsInput toolsInput1 = ToolsInput();
                toolsInput1.ToolName = ToolTypeToString(ToolType::Cross);
                toolsInput1.InputEleName = selectEles.at(0)->m_strElementName;
                toolsInput1.InputEleID = selectEles.at(0)->m_strElementUid;
                toolsInputs.push_back(toolsInput1);
                ToolsInput toolsInput2 = ToolsInput();
                toolsInput2.ToolName = ToolTypeToString(ToolType::Cross);
                toolsInput2.InputEleName = selectEles.at(1)->m_strElementName;
                toolsInput2.InputEleID = selectEles.at(1)->m_strElementUid;
                toolsInputs.push_back(toolsInput2);
                this->toolTypes[ToolType::Cross] = toolsInputs;
                CElementBase* element1 = selectEles.at(0);
                CElementBase* element2 = selectEles.at(1);
                if (element1->nType == ELE_PLANE && element2->nType == ELE_PLANE) //面面交叉
                {
                        
                        auto  pairs = GetPlansCrossLine(element1, element2);
                        gp_Pnt startPo = std::get<0>(pairs);
                        gp_Pnt endPo = std::get<1>(pairs);
                        if (startPo.IsEqual(endPo, 1e-6))
                                return false;
                        this->mcs_Start = startPo;
                        this->mcs_End = endPo;
                        double z = (this->mcs_Start.Z() + this->mcs_End.Z()) * 0.5;
                        this->mcs_Start.SetZ(z);
                        this->mcs_End.SetZ(z);
                        this->Length = this->mcs_Start.Distance(this->mcs_End);
                }
                this->m_pMCS->McsPosition = (this->mcs_Start.XYZ() + this->mcs_End.XYZ()) * 0.5;
                this->ParentUid = parentEle->m_strElementUid;
                this->m_elementOffset.BefMcsPoint = this->m_pMCS->McsPosition;
                this->IsUesedToolTypes[Cross] = true;
                this->ConSubPoints.clear();
                return true;
        }
        catch (const std::exception& ex)
        {
                std::cerr << "Exception caught: " << ex.what() << std::endl;
                this->toolTypes[ToolType::Cross] = toolsInputs;
                this->IsUesedToolTypes[Cross] = false;
                return false;
        }

}

/// <summary>
/// 平分线
/// </summary>
/// <param name="selectEles"></param>
/// <param name="parentEle"></param>
bool EleLine::LineBisector(vector<CElementBase*> selectEles, CElementBase* parentEle)
{
        list<ToolsInput> toolsInputs = list<ToolsInput>();
        try
        {
                ToolsInput toolsInput1 = ToolsInput();
                toolsInput1.ToolName = ToolTypeToString(ToolType::Bisector);
                toolsInput1.InputEleName = selectEles.at(0)->m_strElementName;
                toolsInput1.InputEleID = selectEles.at(0)->m_strElementUid;
                toolsInputs.push_back(toolsInput1);
                ToolsInput toolsInput2 = ToolsInput();
                toolsInput2.ToolName = ToolTypeToString(ToolType::Bisector);
                toolsInput2.InputEleName = selectEles.at(1)->m_strElementName;
                toolsInput2.InputEleID = selectEles.at(1)->m_strElementUid;
                toolsInputs.push_back(toolsInput2);
                this->toolTypes[ToolType::Bisector] = toolsInputs;
                CElementBase* element1 = selectEles.at(0);
                CElementBase* element2 = selectEles.at(1);
                CElementBase* lineSegment1;
                bool isLine1 = FuncBase::GetLineSegment(element1, &lineSegment1);
                CElementBase* lineSegment2;
                bool isLine2 = FuncBase::GetLineSegment(element2, &lineSegment2);
                Alignment* myCoord = ((Alignment*)parentEle);
                gp_Pln myPlane = FuncBase::GetWorkingPlane(parentEle);
                gp_Pnt mcsPt;
                // 线线平分
                if (isLine1 && isLine2)
                {
                        vector<CElementBase> elements = vector<CElementBase>();
                        EleLine* line1 = (EleLine*)lineSegment1;
                        EleLine* line2 = (EleLine*)lineSegment2;
                        auto start_end1 = line1->GetLineMcsStartEndPoint();
                        gp_Pnt line1_mcsStart = get<0>(start_end1);
                        gp_Pnt line1_mcsEnd = get<1>(start_end1);
                        auto start_end2 = line2->GetLineMcsStartEndPoint();
                        gp_Pnt line2_mcsStart = get<0>(start_end2);
                        gp_Pnt line2_mcsEnd = get<1>(start_end2);
                        mcsPt = (line1->m_pMCS->McsPosition.XYZ() + line2->m_pMCS->McsPosition.XYZ()) * 0.5;
                        line1_mcsStart = MathHelper::FindClosestPointOnPlane(myPlane, line1_mcsStart);
                        line1_mcsEnd = MathHelper::FindClosestPointOnPlane(myPlane, line1_mcsEnd);
                        line2_mcsStart = MathHelper::FindClosestPointOnPlane(myPlane, line2_mcsStart);
                        line2_mcsEnd = MathHelper::FindClosestPointOnPlane(myPlane, line2_mcsEnd);

                        auto result = MathHelper::CalculateBisectorAndTangent(line1_mcsStart, line1_mcsEnd, line2_mcsStart, line2_mcsEnd);
                        gp_Pnt midpt1 = (line1_mcsStart.XYZ() + line1_mcsEnd.XYZ()) * 0.5;
                        gp_Pnt midpt2 = (line2_mcsStart.XYZ() + line2_mcsEnd.XYZ()) * 0.5;
                        BRepAlgoAPI_Section intersection1(BRepBuilderAPI_MakeEdge(midpt1, midpt2),
                                BRepBuilderAPI_MakeEdge(std::get<0>(result.at(0)), std::get<1>(result.at(0))).Edge());

                        BRepAlgoAPI_Section intersection2(BRepBuilderAPI_MakeEdge(midpt1, midpt2),
                                BRepBuilderAPI_MakeEdge(std::get<0>(result.at(1)), std::get<1>(result.at(1))).Edge());
                        // 输出交点结果
                        TopoDS_Shape resultshape1 = intersection1.Shape();
                        TopoDS_Shape resultshape2 = intersection2.Shape();
                        if (resultshape1.IsNull() || resultshape2.IsNull()) {
                                return false;
                        }
                        else
                        {
                                if (!resultshape2.IsNull())
                                {
                                        auto tempresult = result;
                                        result.clear();
                                        result.push_back(tempresult.at(1));
                                        result.push_back(tempresult.at(0));
                                }
                        }
                        
                        vector<pair<gp_Pnt, gp_Pnt>> conResult;
                        gp_Pnt pcs_pt = FuncBase::ConvertToV2(myCoord, mcsPt);
                        for (auto myPair : result)
                        {
                                gp_Pnt pcs_Start = FuncBase::ConvertToV2(myCoord, std::get<0>(myPair));
                                gp_Pnt pcs_End = FuncBase::ConvertToV2(myCoord, std::get<1>(myPair));
                                switch (myCoord->workingPlaneIdx)
                                {
                                case 0:
                                        pcs_Start.SetZ(pcs_pt.Z());
                                        pcs_End.SetZ(pcs_pt.Z());
                                        break;
                                case 1:
                                        pcs_Start.SetX(pcs_pt.X());
                                        pcs_End.SetX(pcs_pt.X());
                                        break;
                                case 2:
                                        pcs_Start.SetY(pcs_pt.Y());
                                        pcs_End.SetY(pcs_pt.Y());
                                        break;
                                default:
                                        break;
                                }

                                conResult.push_back({ FuncBase::ConvertPcsToMcs(myCoord, pcs_Start),FuncBase::ConvertPcsToMcs(myCoord, pcs_End) });
                                
                        }
               
                        
                        auto solutions = DealWithLineBisector(conResult, selectEles, parentEle);
                        switch (m_nSolutionIndex)
                        {
                        case -1:  
                                if (mySolutCallback)
                                        mySolutCallback(solutions);
                                break;
                        case 0:
                                this->mcs_Start = ((EleLine*)solutions.at(0))->mcs_Start;
                                this->mcs_End = ((EleLine*)solutions.at(0))->mcs_End;
                                break;
                        case 1:
                                this->mcs_Start = ((EleLine*)solutions.at(1))->mcs_Start;
                                this->mcs_End = ((EleLine*)solutions.at(1))->mcs_End;
                                break;
                        default:
                                break;
                        }
                        this->m_pMCS->McsPosition = (this->mcs_Start.XYZ() + this->mcs_End.XYZ()) * 0.5f;;
                        this->Length = this->mcs_Start.Distance(this->mcs_End);
                }
                // 线和非线特征平分
                if (!isLine1 && isLine2 || isLine1 && !isLine2)
                {
                        auto NoLeelement = !isLine1 ? element1 : element2;
                        auto Lelement = isLine1 ? (EleLine*)lineSegment1 : (EleLine*)lineSegment2;
                        auto LelementStart_end = Lelement->GetLineMcsStartEndPoint();
                        gp_Pnt line_mcsStart = get<0>(LelementStart_end);
                        gp_Pnt line_mcsEnd = get<1>(LelementStart_end);
                        gp_Pnt centerNoLPo = NoLeelement->GetMcsPosition();
                        gp_Pnt centerLPo = Lelement->GetMcsPosition();
                        mcsPt = (centerNoLPo.XYZ() + centerLPo.XYZ()) * 0.5;
                        this->Length = Lelement->Length;
                        this->m_pMCS->McsPosition = (centerNoLPo.XYZ() + centerLPo.XYZ()) * 0.5f;
                        line_mcsStart = MathHelper::FindClosestPointOnPlane(myPlane, line_mcsStart);
                        line_mcsEnd = MathHelper::FindClosestPointOnPlane(myPlane, line_mcsEnd);
                        // 计算线段的方向向量算出平分线的中心点偏移
                        gp_Vec direction = gp_Vec(line_mcsStart, line_mcsEnd);
                        direction.Normalize();
                        double distance = this->Length * 0.5f;
                        this->mcs_Start = this->m_pMCS->McsPosition.XYZ() + (direction * distance).XYZ();
                        this->mcs_End = this->m_pMCS->McsPosition.XYZ() - (direction * distance).XYZ();

                        gp_Pnt pcs_Start = FuncBase::ConvertToV2(myCoord, this->mcs_Start);
                        gp_Pnt pcs_End = FuncBase::ConvertToV2(myCoord, this->mcs_End);
                        gp_Pnt pcs_pt = FuncBase::ConvertToV2(myCoord, mcsPt);
                        switch (myCoord->workingPlaneIdx)
                        {
                        case 0:
                                pcs_Start.SetZ(pcs_pt.Z());
                                pcs_End.SetZ(pcs_pt.Z());
                                break;
                        case 1:
                                pcs_Start.SetX(pcs_pt.X());
                                pcs_End.SetX(pcs_pt.X());
                                break;
                        case 2:
                                pcs_Start.SetY(pcs_pt.Y());
                                pcs_End.SetY(pcs_pt.Y());
                                break;
                        default:
                                break;
                        }
                        this->mcs_Start = FuncBase::ConvertPcsToMcs(myCoord, pcs_Start);
                        this->mcs_End = FuncBase::ConvertPcsToMcs(myCoord, pcs_End);
                        this->m_pMCS->McsPosition = (this->mcs_Start.XYZ() + this->mcs_End.XYZ()) * 0.5;
                }

                // 非线特征平分线
                if (!isLine1 && !isLine2)
                {
                        auto element1CenterPo = element1->GetMcsPosition();
                        auto element2CenterPo = element2->GetMcsPosition();
                        mcsPt = (element1CenterPo.XYZ() + element2CenterPo.XYZ()) * 0.5;
                        // 两个中心点间的距离

                        this->Length = element1CenterPo.Distance(element2CenterPo);
                        double distance = (double)this->Length * 0.5f;
                        // 宽度需重新设置这里默认1
                        element1CenterPo = MathHelper::FindClosestPointOnPlane(myPlane, element1CenterPo);
                        element2CenterPo = MathHelper::FindClosestPointOnPlane(myPlane, element2CenterPo);
                        gp_Pnt pcs_pt = FuncBase::ConvertToV2(myCoord, mcsPt);
                        element1CenterPo = FuncBase::ConvertToV2(myCoord, element1CenterPo);
                        element2CenterPo = FuncBase::ConvertToV2(myCoord, element2CenterPo);


                        switch (myCoord->workingPlaneIdx)
                        {
                        case 0:
                                element1CenterPo.SetZ(pcs_pt.Z());
                                element2CenterPo.SetZ(pcs_pt.Z());
                                break;
                        case 1:
                                element1CenterPo.SetX(pcs_pt.X());
                                element2CenterPo.SetX(pcs_pt.X());
                                break;
                        case 2:
                                element1CenterPo.SetY(pcs_pt.Y());
                                element2CenterPo.SetY(pcs_pt.Y());
                                break;
                        default:
                                break;
                        }
                        element1CenterPo = FuncBase::ConvertPcsToMcs(myCoord, element1CenterPo);
                        element2CenterPo = FuncBase::ConvertPcsToMcs(myCoord, element2CenterPo);
                        this->m_pMCS->McsPosition = (element1CenterPo.XYZ() + element2CenterPo.XYZ()) * 0.5;
                        // 两个中心点的方向向量
                        gp_Vec direction = gp_Vec(element1CenterPo, element2CenterPo);

                        // 与两个中心点垂直的方向向量也就是平分线的向量
                        gp_Vec normal = gp_Vec(-direction.Y(), direction.X(), direction.Z());
                        normal.Normalize();
                        // 向量归一化处理
                        gp_Pnt lineSegmentSatrtPo = this->m_pMCS->McsPosition.XYZ() + (normal * distance).XYZ();
                        gp_Pnt lineSegmentEndPo = this->m_pMCS->McsPosition.XYZ() - (normal * distance).XYZ();
                        this->mcs_Start = lineSegmentSatrtPo;
                        this->mcs_End = lineSegmentEndPo;
                }
                this->ParentUid = parentEle->m_strElementUid;

                this->m_elementOffset.BefMcsPoint = this->m_pMCS->McsPosition;
                this->IsUesedToolTypes[Bisector] = true;
                this->ConSubPoints.clear();
                return true;
        }
        catch (const std::exception& ex)
        {
                std::cerr << "Exception caught: " << ex.what() << std::endl;
                this->toolTypes[ToolType::Bisector] = toolsInputs;
                this->IsUesedToolTypes[Bisector] = false;
                return false;
        }

}

/// <summary>
/// 处理线的平分
/// </summary>
/// <param name="resultLinePair"></param>
/// <param name="seletEles"></param>
/// <param name="parentEle"></param>
/// <returns></returns>
vector<CElementBase*> EleLine::DealWithLineBisector(vector<pair<gp_Pnt, gp_Pnt>> resultLinePair, vector<CElementBase*> seletEles, CElementBase* parentEle)
{
        vector<CElementBase*> elements = vector<CElementBase*>();
        for (auto line : resultLinePair)
        {
                list<ToolsInput> toolsInputs = list<ToolsInput>();
                EleLine* elementLine = (EleLine*)((EleLine*)this)->Clone();
                elementLine->ParentUid = parentEle->m_strElementUid;
                elementLine->mcs_Start = line.first;
                elementLine->mcs_End = line.second;
                elementLine->Length = elementLine->mcs_Start.Distance(elementLine->mcs_End);
                elementLine->m_pMCS->McsPosition = (elementLine->mcs_Start.XYZ() + elementLine->mcs_End.XYZ()) * 0.5f;
                elementLine->Tag = Special;
                elementLine->solution_Tag = "BISECTOR";
                elementLine->m_pPCS->PcsPosition = FuncBase::ConvertToV2(parentEle, elementLine->m_pMCS->McsPosition);
                elementLine->m_elementOffset.BefMcsPoint = elementLine->m_pPCS->PcsPosition;
                elementLine->m_strElementUid = MathHelper::GenerateGuid();
                elementLine->IsUesedToolTypes[TangentLine] = true;
                elements.push_back(elementLine);
        }
        elements.at(0)->solutionSubTag = SOLUTIONSUBTYPE::MID;
        elements.at(1)->solutionSubTag = SOLUTIONSUBTYPE::SUPPER;
        elements.at(0)->m_nSolutionIndex = 0;
        elements.at(1)->m_nSolutionIndex = 1;
        elements.push_back(seletEles.at(0));
        elements.push_back(seletEles.at(1));
        return elements;
}

tuple<gp_Pnt, gp_Pnt> EleLine::GetPlansCrossLine(CElementBase* ele1, CElementBase* ele2)
{
        ElePlane* plane1 = ((ElePlane*)ele1);
        ElePlane* plane2 = ((ElePlane*)ele2);
        TopoDS_Face face1 = CreateFace(plane1);
        TopoDS_Face face2 = CreateFace(plane2);
        // 计算面面交线
        BRepAlgoAPI_Section section(face1, face2);
        section.Build(); // 必须调用Build()生成结果

        if (!section.IsDone()) {
                // 错误处理:交线不存在或计算失败
                return { gp_Pnt(0,0,0),gp_Pnt(0,0,0) };
        }

        // 提取交线结果
        const TopoDS_Shape& result = section.Shape();

        // 遍历结果中的边(Edge)
        TopExp_Explorer explorer(result, TopAbs_EDGE);

        vector<gp_Pnt> listPoints = vector<gp_Pnt>();
        for (; explorer.More(); explorer.Next()) {
                const TopoDS_Edge& edge = TopoDS::Edge(explorer.Current());

                // 获取边的几何曲线
                Standard_Real start, end;
                Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, start, end);

                // 如果是直线(两平面交线为直线)
                if (curve->DynamicType() == STANDARD_TYPE(Geom_Line)) {
                        Handle(Geom_Line) line = Handle(Geom_Line)::DownCast(curve);
                        //取点和直线的交点
                        for (gp_Pnt po : plane1->pointsCorners)
                        {
                                //点与直线做垂线,得出拟合直线的交点
                                gp_Pnt intersectionP = MathHelper::projectPointOntoLine(po, line->Lin());
                                listPoints.push_back(intersectionP);
                        }
                        for (gp_Pnt po : plane2->pointsCorners)
                        {
                                //点与直线做垂线,得出拟合直线的交点
                                gp_Pnt intersectionP = MathHelper::projectPointOntoLine(po, line->Lin());
                                listPoints.push_back(intersectionP);
                        }
                        tuple<gp_Pnt, gp_Pnt> pairs = MathHelper::GetFitLine(listPoints);
                        
                        return pairs;
                }
                else
                {
                        return { gp_Pnt(0,0,0),gp_Pnt(0,0,0) };
                }

        }

        return { gp_Pnt(0,0,0),gp_Pnt(0,0,0) };
}

TopoDS_Face EleLine::CreateFace(CElementBase* ele1)
{
        ElePlane* plane = ((ElePlane*)ele1);
        BRepBuilderAPI_MakeEdge edge1(plane->pointsCorners.at(0), plane->pointsCorners.at(1));
        BRepBuilderAPI_MakeEdge edge2(plane->pointsCorners.at(1), plane->pointsCorners.at(2));
        BRepBuilderAPI_MakeEdge edge3(plane->pointsCorners.at(2), plane->pointsCorners.at(3));
        BRepBuilderAPI_MakeEdge edge4(plane->pointsCorners.at(3), plane->pointsCorners.at(0));
        // 将边创建成一个线框(Wire)
        BRepBuilderAPI_MakeWire wire;
        wire.Add(edge1.Edge());
        wire.Add(edge2.Edge());
        wire.Add(edge3.Edge());
        wire.Add(edge4.Edge());
        // 创建面
        BRepBuilderAPI_MakeFace makeFace(wire.Wire());
        TopoDS_Face face = makeFace.Face();
        return face;
}

tuple<gp_Pnt, gp_Pnt> EleLine::GetLineMcsStartEndPoint()
{
        gp_Pnt lineStart = this->mcs_Start;
        gp_Pnt lineEnd = this->mcs_End;
        if (this->m_elementOffset.m_bIsOffseted)
        {
                lineStart = FuncBase::GetMatrixPoint(this, this->mcs_Start);
                lineEnd = FuncBase::GetMatrixPoint(this, this->mcs_End);
        }
        return make_tuple(lineStart, lineEnd);
}

/// <summary>
/// 最小范围
/// </summary>
/// <param name="selectEles"></param>
/// <param name="parentEle"></param>
/// <returns></returns>
bool EleLine::LineMinimunRange(vector<CElementBase*> selectEles, CElementBase* parentEle)
{
        list<ToolsInput> toolsInputs = list<ToolsInput>();
        try
        {
                vector<gp_Pnt> points = vector<gp_Pnt>();
                for (CElementBase* element : selectEles)
                {
                        if (element->nType == ELE_LINE || element->nType == ELE_OPEN_CLOUD_LINE ||
                                element->nType == ELE_POINT_CLOUD)
                        {
                                // Insert all features from points1 into PointF
                                this->PointF.insert(PointF.end(), element->PointF.begin(), element->PointF.end());

                                toolsInputs.push_back(ToolsInput{ ToolTypeToString(ToolType::RingZone),element->m_strElementName,element->m_strElementUid });
                                points.insert(points.end(), element->PointF.begin(), element->PointF.end());
                        }
                        else
                        {
                                points.push_back(element->GetMcsPosition());
                                this->PointF.push_back(element->GetMcsPosition());
                                toolsInputs.push_back(ToolsInput{ ToolTypeToString(ToolType::RingZone),element->m_strElementName,element->m_strElementUid });
                        }
                }
                tuple<gp_Pnt, gp_Pnt>  vectors = tuple<gp_Pnt, gp_Pnt>{ points.at(0), points.at(1) };
                if (points.size() > 2)
                {
                        // 进行切比雪夫拟合直线
                        vectors = MathHelper::FitLineToPointCloud(points);
                }

                gp_Pnt startPoint = std::get<0>(vectors);
                gp_Pnt endPoint = std::get<1>(vectors);
                this->mcs_Start = startPoint;
                this->mcs_End = endPoint;
                double z = (this->mcs_Start.Z() + this->mcs_End.Z()) * 0.5;
                this->mcs_Start.SetZ(z);
                this->mcs_End.SetZ(z);
                this->m_pMCS->McsPosition = (this->mcs_Start.XYZ() + this->mcs_End.XYZ()) * 0.5f;
                this->Length = this->mcs_Start.Distance(this->mcs_End);
                this->m_pPCS->PcsPosition = FuncBase::ConvertToV2(parentEle, this->m_pMCS->McsPosition);
                this->m_elementOffset.BefMcsPoint = this->m_pMCS->McsPosition;
                this->toolTypes[ToolType::MinimumRange] = toolsInputs;
                this->IsUesedToolTypes[MinimumRange] = true;
                return true;

        }
        catch (const std::exception& ex)
        {
                std::cerr << "Exception caught: " << ex.what() << std::endl;
                this->toolTypes[ToolType::MinimumRange] = toolsInputs;
                this->IsUesedToolTypes[MinimumRange] = false;
                this->m_pPCS->PcsPosition = FuncBase::ConvertToV2(parentEle, this->m_pMCS->McsPosition);
                this->m_elementOffset.BefMcsPoint = this->m_pMCS->McsPosition;
                return false;
        }
}

/// <summary>
/// 呼出
/// </summary>
/// <param name="selectEle"></param>
/// <param name="parentEle"></param>
/// <returns></returns>
bool EleLine::CallOutLine(CElementBase* selectEle, CElementBase* parentEle)
{
        list<ToolsInput> toolsInputs = list<ToolsInput>();
        if (selectEle->nType == ELE_LINE)
        {
                EleLine* element = (EleLine*)(selectEle);
                this->m_pMCS->McsPosition = element->GetMcsPosition();
                auto start_end = element->GetLineMcsStartEndPoint();
                gp_Pnt line_mcsStart = get<0>(start_end);
                gp_Pnt line_mcsEnd = get<1>(start_end);
                this->mcs_Start = line_mcsStart;
                this->mcs_End = line_mcsEnd;
                this->Length = mcs_Start.Distance(mcs_End);
                this->vec_Line = element->vec_Line;
                this->PointF = element->GetPointF();
                this->ParentUid = parentEle->m_strElementUid;
                this->m_pPCS->PcsPosition = FuncBase::ConvertToV2(parentEle, this->m_pMCS->McsPosition);
                this->m_elementOffset.BefMcsPoint = this->m_pMCS->McsPosition;
                toolsInputs.push_back(ToolsInput{ ToolTypeToString(ToolType::PointsInput) ,selectEle->m_strElementName,selectEle->m_strElementUid });
                this->toolTypes[ToolType::callOut] = toolsInputs;
                this->IsUesedToolTypes[callOut] = true;
                return true;
        }
        else
        {
                this->m_pPCS->PcsPosition = FuncBase::ConvertToV2(parentEle, this->m_pMCS->McsPosition);
                this->m_elementOffset.BefMcsPoint = this->m_pMCS->McsPosition;
                this->toolTypes[ToolType::callOut] = toolsInputs;
                this->IsUesedToolTypes[callOut] = false;
                return false;
        }
}


vector<gp_Pnt> EleLine::readPointsFromFile(std::string filename) {
        std::vector<gp_Pnt> points;
        std::ifstream file(filename);

        if (!file.is_open()) {
                std::cerr << "Error opening file: " << filename << std::endl;
                return points;
        }

        std::string line;
        while (std::getline(file, line)) {
                // 查找x和y的位置
                size_t x_pos = line.find("x=");
                size_t y_pos = line.find("y=");

                if (x_pos != std::string::npos && y_pos != std::string::npos)
                {
                        // 提取x值
                        std::string x_str = line.substr(x_pos + 2);
                        x_str = x_str.substr(0, x_str.find(' '));

                        // 提取y值
                        std::string y_str = line.substr(y_pos + 2);
                        y_str = y_str.substr(0, y_str.find(' '));

                        try {
                                double x = std::stod(x_str);
                                double y = std::stod(y_str);
                                points.emplace_back(x, y, 0.0); // z坐标设为0
                        }
                        catch (const std::exception& e)
                        {
                                std::cerr << "Exception caught: " << e.what() << std::endl;
                                std::cerr << "Error parsing line: " << line << std::endl;
                        }
                }
        }

        file.close();
        return points;
}


/// <summary>
/// 选择点圆/弧/椭圆的切线
/// </summary>
/// <param name="element">要构造的特征</param>
/// <param name="inputElement">圆/弧/椭圆</param>
/// <param name="point">点</param>
/// <param name="inputElements">特征列表</param>
/// <param name="parentEle">父特征</param>
/// <param name="isTowCircle">是否是圆圆</param>
vector<CElementBase*> EleLine::PointCircleTangenLine(CElementBase* element, CElementBase* inputElement, const gp_Pnt& point, vector<CElementBase*> inputElements, CElementBase* parentEle, bool isTowCircle)
{
        gp_Pnt point1;
        gp_Pnt point2;
        if (inputElements[0]->GetMcsPosition().IsEqual(inputElements.at(1)->GetMcsPosition(), 1e-6))
                return vector<CElementBase*>();
        vector<pair<gp_Pnt, gp_Pnt>> dicLines = vector<pair<gp_Pnt, gp_Pnt>>();
        if (isTowCircle)//圆圆切线
        {
                double radius1 = FuncBase::GetRadius(inputElements.at(0));
                double radius2 = FuncBase::GetRadius(inputElements.at(1));
                dicLines = MathHelper::CalculateTangentLineCircle(inputElements[0]->GetMcsPosition(), radius1, inputElements.at(1)->GetMcsPosition(), radius2);
        }
        else
        {
                //点圆切线
                double radius = FuncBase::GetRadius(inputElement);
                dicLines = MathHelper::CalculateTangents(inputElement->GetMcsPosition(), radius, point, point1, point2);
                if (inputElement->nType == ELE_ELLIPSE)
                {
                        auto ellipse = (EleEllipse*)inputElement;
                        dicLines = MathHelper::CalculateTangent_Ellipse(ellipse->GetMcsPosition(), 2 * (double)ellipse->maxjorAxis, 2 * (double)ellipse->minorAxis
                                , ellipse->rotateAngle, point, point1, point2);
                }
        }
        ((EleLine*)element)->mcs_Start = point1;
        ((EleLine*)element)->mcs_End = point2;
        ((EleLine*)element)->m_pMCS->McsPosition = (((EleLine*)element)->mcs_Start.XYZ() + ((EleLine*)element)->mcs_End.XYZ()) * 0.5f;
        if (dicLines.size() == 0)
                return vector<CElementBase*>();
        vector<CElementBase*> elements = vector<CElementBase*>();
        int index = 0;

        Alignment* myCoord = ((Alignment*)parentEle);
        gp_Pln myPlane = FuncBase::GetWorkingPlane(parentEle);
        gp_Pnt mcsPt;
        for (auto line : dicLines)
        {
                list<ToolsInput> toolsInputs = list<ToolsInput>();
                toolsInputs.push_back(ToolsInput{ ToolTypeToString(ToolType::TangentLine), inputElements.at(0)->m_strElementName, inputElements.at(0)->m_strElementUid });
                toolsInputs.push_back(ToolsInput{ ToolTypeToString(ToolType::TangentLine), inputElements.at(1)->m_strElementName, inputElements.at(1)->m_strElementUid });
                EleLine* elementLine = (EleLine*)((EleLine*)element)->Clone();
                elementLine->ParentUid = parentEle->m_strElementUid;
                elementLine->mcs_Start = line.first;
                elementLine->mcs_End = line.second;

                mcsPt = (elementLine->mcs_Start.XYZ() + elementLine->mcs_End.XYZ()) * 0.5;
                elementLine->mcs_Start = MathHelper::FindClosestPointOnPlane(myPlane, elementLine->mcs_Start);
                elementLine->mcs_End = MathHelper::FindClosestPointOnPlane(myPlane, elementLine->mcs_End);
                gp_Pnt pcs_pt = FuncBase::ConvertToV2(myCoord, mcsPt);
                elementLine->mcs_Start = FuncBase::ConvertToV2(myCoord, elementLine->mcs_Start);
                elementLine->mcs_End = FuncBase::ConvertToV2(myCoord, elementLine->mcs_End);


                switch (myCoord->workingPlaneIdx)
                {
                case 0:
                        elementLine->mcs_Start.SetZ(pcs_pt.Z());
                        elementLine->mcs_End.SetZ(pcs_pt.Z());
                        break;
                case 1:
                        elementLine->mcs_Start.SetX(pcs_pt.X());
                        elementLine->mcs_End.SetX(pcs_pt.X());
                        break;
                case 2:
                        elementLine->mcs_Start.SetY(pcs_pt.Y());
                        elementLine->mcs_End.SetY(pcs_pt.Y());
                        break;
                default:
                        break;
                }
                elementLine->mcs_Start = FuncBase::ConvertPcsToMcs(myCoord, elementLine->mcs_Start);
                elementLine->mcs_End = FuncBase::ConvertPcsToMcs(myCoord, elementLine->mcs_End);

                elementLine->Length = elementLine->mcs_Start.Distance(elementLine->mcs_End);
                elementLine->m_pMCS->McsPosition = (elementLine->mcs_Start.XYZ() + elementLine->mcs_End.XYZ()) * 0.5f;
                elementLine->Tag = Special;
                elementLine->m_elementOffset.BefMcsPoint = elementLine->m_pPCS->PcsPosition;
                elementLine->m_strElementUid = MathHelper::GenerateGuid();
                elementLine->toolTypes[ToolType::TangentLine] = toolsInputs;
                elementLine->IsUesedToolTypes[TangentLine] = true;
                elementLine->m_nSolutionIndex = index++;
                elements.push_back(elementLine);
        }
        elements.push_back(inputElements.at(0));
        elements.push_back(inputElements.at(1));
        return elements;
}

GeomAdaptor_Curve EleLine::GetCurve()
{
        GeomAdaptor_Curve adaptorCurve;
        gp_Pnt startP = this->mcs_Start;
        gp_Pnt endP = this->mcs_End;
        if (startP.XYZ().IsEqual(endP.XYZ(), 1.0e-9))
                return adaptorCurve;
        //处理特征偏移
        auto points = FuncBase::ElementOffset(this);
        if (points.size() > 0)
        {
                startP = points[0];
                endP = points[1];
        }

        gp_Vec myVec(startP, endP);
        gp_Ax1 gpax(startP, myVec);
        Handle_Geom_Line theLine = new Geom_Line(gpax);
    adaptorCurve  = GeomAdaptor_Curve(theLine);
        return adaptorCurve;
}

您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|Archiver|小黑屋|几何尺寸与公差论坛

GMT+8, 2026-5-21 05:16 , Processed in 0.060609 second(s), 19 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表