之前有手写的约束求解(CSDNBMBase二次开发 C++ 创建直线约束求解器_bpentitycr-CSDN博客CSDN),但是在涉及到跨对象约束太多的时候,就会产生很多计算上的错误。所以现在改用了调用PlaneGCS来求解(PlaneGCS包下载地址:FreeCAD/src/Mod/Sketcher/App/planegcs at main · FreeCAD/FreeCAD · GitHub)。用PlaneGCS来求解,只需要把约束添加到求解器里面,然后求解,如果求解成功,那么再把求解器里面的参数赋值到BIMBase里面的自定义直线上,并且更新约束图像,就完成了约束。也参考了PlaneGCS-平面几何约束求解器用法 - opencascade - 博客园 (cnblogs.com)这篇文章,后续就是自己慢慢摸索调试修改完后的内容。
1.添加约束参数到求解器
GCS::Point aP1(new double(pbLine.getStartPoint().x), new double(pbLine.getStartPoint().y));
GCS::Point aP2(new double(pbLine.getEndPoint().x), new double(pbLine.getEndPoint().y));
GCS::Line aLine1;
aLine1.p1 = aP1;
aLine1.p2 = aP2;
aParameters.push_back(aLine1.p1.x);
aParameters.push_back(aLine1.p1.y);
aParameters.push_back(aLine1.p2.x);
aParameters.push_back(aLine1.p2.y);
int lineId = pbLine.m_nLineId;
// 插入时使用 make_unique 或 make_shared
Line_GCS.insert(std::make_pair(lineId, std::make_unique<GCS::Line>(aLine1)));
2.添加约束
由于PlaneGCS并没有水平距离、垂直距离和共点这些约束,只有倍数相等,差值等约束,所以在添加所叙的这些约束时,就需要用它的已有约束去构造这些约束。
switch (nConstraintType)
{
case 1://水平距离
{
if (nLineNum != -1 && nNextGraphicElementID <= 0)//与原点的约束
{
nRet = aSolver.addConstraintDifference(aP1.x, aP2.x, new double(dConstrainValue));
GCS::Constraint* constr6 = new GCS::ConstraintEqual(aP1.x, new double(0.00));
nRet = aSolver.addConstraint(constr6);
GCS::Constraint* constr7 = new GCS::ConstraintEqual(aP1.y, new double(0.00));
nRet = aSolver.addConstraint(constr7);
aParameters.push_back(new double(0.00));
}
else if (nConstraintDim_ID == nLineID || nNextGraphicElementID <= 0)
nRet = aSolver.addConstraintDifference(aP1.x, aP2.x, new double(dConstrainValue));
else
nRet = aSolver.addConstraintDifference(aP2.x, aP1.x, new double(dConstrainValue));
aParameters.push_back(new double(dConstrainValue));
return nRet;
}
case 2://垂直距离
{
if (nLineNum != -1 && nNextGraphicElementID <= 0)//与原点的约束
{
nRet = aSolver.addConstraintDifference(aP1.y, aP2.y, new double(dConstrainValue));
GCS::Constraint* constr6 = new GCS::ConstraintEqual(aP1.x, new double(0.00));
nRet = aSolver.addConstraint(constr6);
GCS::Constraint* constr7 = new GCS::ConstraintEqual(aP1.y, new double(0.00));
nRet = aSolver.addConstraint(constr7);
aParameters.push_back(new double(0.00));
}
else if (nConstraintDim_ID == nLineID || nNextGraphicElementID <= 0)
nRet = aSolver.addConstraintDifference(aP1.y, aP2.y, new double(dConstrainValue));
else
nRet = aSolver.addConstraintDifference(aP2.y, aP1.y, new double(dConstrainValue));
aParameters.push_back(new double(dConstrainValue));
return nRet;
}
case 3://水平
{
GCS::Constraint* constr = new GCS::ConstraintEqual(aP1.y, aP2.y);
nRet = aSolver.addConstraint(constr);
return nRet;
}
case 4://垂直
{
GCS::Constraint* constr = new GCS::ConstraintEqual(aP1.x, aP2.x);
nRet = aSolver.addConstraint(constr);
return nRet;
}
case 5://共点
{
GCS::Constraint* constr1 = new GCS::ConstraintEqual(aP1.x, aP2.x);
GCS::VEC_pD vecParam1 = constr1->params();
for (auto iter_param : vecParam1)
aParameters.push_back(iter_param);
GCS::Constraint* constr2 = new GCS::ConstraintEqual(aP1.y, aP2.y);
GCS::VEC_pD vecParam2 = constr2->params();
for (auto iter_param : vecParam2)
aParameters.push_back(iter_param);
aSolver.addConstraint(constr1);
nRet = aSolver.addConstraint(constr2);
return nRet;
}
}
3.约束求解和赋值给BIMBase的自定义直线
在上面的添加约束参数到求解器 这一步的时候,就把参数添加到aParameters,由于都是指针,求解完后只就把这些指针指向的值拿出来赋值给里自定义直线,然后直线再调用::p3d::P3DStatus replaceInProject(::BIMBase::Core::BPProjectR project, bool bReCreateGeometry = true)这个函数把直线刷新到求解完以后的正确位置。下述代码就没有再写求解失败的代码,一般求解石板就直接返回false。
if(aSolver.solve(aParameters) == GCS::Success)//约束求解
{
for (const auto& pair : Line_GCS)//把Line_GCS里的值赋值给自定义直线
{
int lineId = pair.first;
GCS::Curve* curvePtr = pair.second.get();
//if (1/*entity.getclassname == L"ATDLine"*/)
GCS::Line* linePtr = dynamic_cast<GCS::Line*>(curvePtr);
BPEntityId GeometryID(modelidd, lineId);
BPEntityPtr ptrEntityLine = pProject->getEntityById(GeometryID);
if (!ptrEntityLine.isValid())
return false;
BPDataPtr ptrData = BPDataUtil::getDataOnEntity(*ptrEntityLine);
if (!ptrData.isValid())
return false;
LineDemo pbline;
pbline.initFromData(*ptrData);
pbline.setStartPoint(GePoint3d::create(*linePtr->p1.x, *linePtr->p1.y, 0));
pbline.setEndPoint(GePoint3d::create(*linePtr->p2.x, *linePtr->p2.y, 0));
pbline.replaceInProject(*pProject);
}
for (auto itre_EntID : vecEntID)//约束图像更新位置
{
BPDataPtr ptrData = ATiDeConstraint::getBPdataByEntityID(itre_EntID, pProject, modelidd);
LineDemo pbLine;
pbLine.initFromData(*ptrData);
strAppName.Format(_T("%s_Id=%d"), L"ATDLine", pbLine.getLineId());
int nConstraintcount = GetPrivateProfileInt(strAppName, _T("ConstraintCount"), 0, PBM_Constraint_INIFile_Path);
if (nConstraintcount <= 0)
return false;
int j = 0;
for (int i = 1; ; i++)
{
strKey.Format(_T("Constrain_%d"), i);
int nConstraintType = GetPrivateProfileInt(strAppName, strKey, 0, PBM_Constraint_INIFile_Path);
if (nConstraintType == 0)//当前约束不存在(有可能被删除)
continue;
j++;
//读取约束值
double dConstrainValue = 0.0;
TCHAR szValue[MAX_PATH + 1] = _T("");
strKey.Format(_T("Constrain_Value_%d"), i);
::GetPrivateProfileString(strAppName, strKey, _T("0"), szValue, MAX_PATH, PBM_Constraint_INIFile_Path);
strValue.Format(_T("%s"), szValue);
dConstrainValue = _wtof(strValue.GetBuffer());
strKey.Format(_T("Constrain_LineNum_%d"), i);
int nLineNum = GetPrivateProfileInt(strAppName, strKey, 0, PBM_Constraint_INIFile_Path);
strKey.Format(_T("Constrain_NextGraphicElementID_%d"), i);
int nNextGraphicElementID = GetPrivateProfileInt(strAppName, strKey, 0, PBM_Constraint_INIFile_Path);
strKey.Format(_T("Constrain_DataID_%d"), i);
int nDimDataID = GetPrivateProfileInt(strAppName, strKey, 0, PBM_Constraint_INIFile_Path);
strKey.Format(_T("Constrain_ClassID_%d"), i);
int nDimClassID = GetPrivateProfileInt(strAppName, strKey, 0, PBM_Constraint_INIFile_Path);
BPDataKey ptrDimDataKey(nDimClassID, BPDataId(nDimDataID));
BPDataPtr ptrDimData = BPDataUtil::getDataByKey(ptrDimDataKey, *pProject);
ConstraintDimensionP CTDim = new ConstraintDimension();
CTDim->initFromData(*ptrDimData);
CTDim->m_dDimensionValue = dConstrainValue;
switch (nConstraintType)
{
case 1:
case 2:
{
if (nNextGraphicElementID <= 0 && nLineNum == -1)
{
CTDim->m_ptStart = pbLine.getStartPoint();
CTDim->m_ptEnd = pbLine.getEndPoint();
}
else if (nNextGraphicElementID <= 0 && nLineNum != -1)
{
CTDim->m_ptStart = GePoint3d::create(0, 0, 0);
CTDim->m_ptEnd = (nLineNum == 0) ? pbLine.getStartPoint() : pbLine.getEndPoint();
}
else
{
strKey.Format(_T("Constrain_LineNum_%d"), i);
int nLineNum = GetPrivateProfileInt(strAppName, strKey, -1, PBM_Constraint_INIFile_Path);
if (nLineNum == 0 || nLineNum == 1)
CTDim->m_ptStart = (nLineNum == 0) ? pbLine.getStartPoint() : pbLine.getEndPoint();
BPDataPtr ptrNextData = ATiDeConstraint::getBPdataByEntityID(nNextGraphicElementID, pProject, modelidd);
LineDemo pbNextLine;
pbNextLine.initFromData(*ptrNextData);
strKey.Format(_T("Constrain_NextLineNum_%d"), i);
int nLineNextNum = GetPrivateProfileInt(strAppName, strKey, -1, PBM_Constraint_INIFile_Path);
if (nLineNextNum == 0 || nLineNextNum == 1)
CTDim->m_ptEnd = (nLineNextNum == 0) ? pbNextLine.getStartPoint() : pbNextLine.getEndPoint();
}
break;
}
case 3:
case 4:
{
CTDim->m_ptStart = pbLine.getStartPoint();
CTDim->m_ptEnd = pbLine.getEndPoint();
break;
}
case 5:
{
CTDim->m_ptStart = pbLine.getStartPoint();
CTDim->m_ptEnd = pbLine.getEndPoint();
strKey.Format(_T("Constrain_LineNum_%d"), i);
int nLineNum = GetPrivateProfileInt(strAppName, strKey, -1, PBM_Constraint_INIFile_Path);
CTDim->m_nPtOnNum = nLineNum;
break;
}
default:
{
AfxMessageBox(ATD_Constraint_Exist_Constraint);
break;
}
}
CTDim->replaceInProject(*pProject);
//在这结束循环
if (j >= nConstraintcount)
break;
}
}
}