MSCE C++ BodyFromLoft(smart solid)的问题

老师好:

     我根据您的例子,做了一个放样测试,希望实现  三个矩形  根据 空间坐标的不同, 做一个类似于T型梁的效果,如果按照两个截面做,没有问题,但是 如果是三个截面,每一个截面左下角顶点相连,作为向导线,从而构成一个实体。

下面代码,报Error in BodyFromLoft的错误,或者 放置不成功。向导线 我也做了一个 ,也不成功。恳请老师 过目,帮忙分析一下具体原因。 代码可以测试执行。

void createLoftSolid(DPoint3dR basePt)
{
	//数据准备阶段
	int x1=150,x2=3650,x3=100,x4=2200,x5=100,x6=3650,x7=150;
	int y1=300,y2=2400,y3=300;
	int x1Len=x1+x2+x3+x4+x5+x6+x7;
	int y1Len=y1+y2+y3;
	//int nKouCaoy=100;
	//int nKouCaox=400;
	//int nKouCaoDx=350;
	int nHigthZ1=800;
	int nHigthZ2=900;
	//int nradius=50;
	
	//构建放样的导向线
	DPoint3d Pts[3];
	Pts[0].x = basePt.x-x4/2; 			Pts[0].y = basePt.y-y2/2; 		Pts[0].z = basePt.z;
	Pts[1].x = basePt.x-x4/2-x3-x2-x1;  Pts[1].y = basePt.y-y1Len/2; 	Pts[1].z = basePt.z+nHigthZ1;
	Pts[2].x = basePt.x-x1Len/2+x1;  	Pts[2].y = basePt.y-y2/2; 		Pts[2].z = basePt.z+nHigthZ1+nHigthZ2;
	/***********************************************************************************************************/
	 // 2 ---- 创建 CurveVectorPtr 数组 存储 CurveVector,并将两个圆
    CurveVectorPtr profileVec[3];   
    //BOUNDARY_TYPE_Outer is important, it can create a closed profile that further makes a solid instead of a sheet
    profileVec[0] = CurveVector::Create(CurveVector::BOUNDARY_TYPE_Outer);
	profileVec[0]->Add(ICurvePrimitive::CreateRectangle (basePt.x-x4/2,basePt.y-y2/2,basePt.x+x4/2,basePt.y+y2/2,basePt.z) );//最下面的矩形 也是最小的
	
    profileVec[1] = CurveVector::Create( CurveVector::BOUNDARY_TYPE_Outer);
	profileVec[1]->Add(ICurvePrimitive::CreateRectangle (basePt.x-x1Len/2,basePt.y-y1Len/2,basePt.x+x1Len/2,basePt.y+y1Len/2,basePt.z+nHigthZ1));//中间的矩形,也是最大的矩形
	
	profileVec[2] = CurveVector::Create( CurveVector::BOUNDARY_TYPE_Outer);
	profileVec[2]->Add(ICurvePrimitive::CreateRectangle (basePt.x-x1Len/2+x1,basePt.y-y2/2,basePt.x+x1Len/2-x1,basePt.y+y2/2,basePt.z+nHigthZ1+nHigthZ2));//最上面的矩形,
	
	DSegment3d seg;	
	seg.Init(Pts[0],Pts[1] );
	CurveVectorPtr guideVec[2];
    guideVec[0] = CurveVector::Create(CurveVector::BOUNDARY_TYPE_Open);
	guideVec[1] = CurveVector::Create(CurveVector::BOUNDARY_TYPE_Open);
	guideVec[0]->Add(ICurvePrimitive::CreateLine(seg));//最下面和中间 两个矩形的连接线 也就是向导线
	seg.Init(Pts[1],Pts[2] );
	guideVec[1]->Add(ICurvePrimitive::CreateLine(seg));//中间和最上面 两个矩形的连接线 也就是向导线
	
		/*//改成一个向导线 也不行。如下
		CurveVectorPtr guideVec;
		guideVec= CurveVector::Create(CurveVector::BOUNDARY_TYPE_Open);
		guideVec->Add(ICurvePrimitive::CreateLineString(Pts , 3));
		*/
	

    // 3 ---- Create Solid by Loft
    ISolidKernelEntityPtr solid;
    DgnModelP             pActiveModel = ISessionMgr::GetActiveDgnModelP();
	//if (SUCCESS != SolidUtil::Create::BodyFromLoft(solid, profileVec, 3, &guideVec, 1, *pActiveModel, false, true))
    if (SUCCESS != SolidUtil::Create::BodyFromLoft(solid, profileVec, 3, guideVec, 2, *pActiveModel, false, true))
        {
        mdlDialog_dmsgsPrint(L"Error in BodyFromLoft");
        return;
        }

    // 4 ---- Convert Solid to EditElementHandle and add it to model
    if (solid.IsValid())
        {
        EditElementHandle eeh;
        SolidUtil::Convert::BodyToElement(eeh, *solid, nullptr, *pActiveModel);
        //DraftingElementSchema::ToElement(eeh, *solid, nullptr, *pActiveModel);
        eeh.AddToModel();
        }

}

  • 我怀疑您的截面(左下角)连接导线后,每个截面并没有跟该点的切线垂直,这样是不能成功loft的。我以前做过一个需求,就是若干个相同的截面,一条导线,因为需要知道导线上面每个点的切线信息,所以我当时用了ORD的一些接口,您可以参考下:

    //Many profiles and curve
    StatusInt PSSubgradePlaceLoftSolidTool::SolidCreateBySections(CurveVectorPtr& profile, CurveVectorPtr& path)
    {
        IBcLinearElPtr element;
        StatusInt status = IBcLinearEl::CreateFromCurveVector(*path, true, element);
    
        DPoint3d start, end;
        DVec3d stVec, endVec;
        element->GetEnds(&start, &end, &stVec, &endVec);
    
        IBcLinearElPointArrayPtr linearPointsP;
        int method = BCLINEAREL_STROKINGMETHOD_EQUALDISTANCE;
    
        int nLen = element->GetLength2d();
    
        linearPointsP = IBcLinearElPointArray::make(element.get(), 0.001);
        status = element->Stroke(linearPointsP.get(), method, nLen / 10, 0, true, 0.001);
        int numPoints = linearPointsP->GetSize();
        if (status != SUCCESS)
        {
            return ERROR;
        }
        DPoint3d pt;
        Transform trans;
        bvector<CurveVectorPtr> profiles;
    
        for (size_t i = 0; i < linearPointsP->GetSize(); i++)
        {
            DVec3d xVec, yVec, zVec;
            RotMatrix rMatrix;
    
            BcLinearElPoint point = linearPointsP->GetPointByIndex(i);
            DPoint3d ptTest = point.GetPoint();
            DPoint3d ptTagTest = point.GetTangent();
            xVec = DVec3d::From(ptTagTest);
    
            pt = linearPointsP->GetPointRAt(i).GetPoint();
    
            CurveVectorPtr curVec2 = profile->Clone();
    
            zVec = DVec3d::From(linearPointsP->GetPointRAt(i).GetTangent());
    
            zVec.Normalize();
            /////////////////////////////////////////////////////////////////////////////////////////////////
            DVec3d wVec;
            wVec = zVec;
            wVec.Scale(50);
            DSegment3d segment;
            DPoint3d vpt;
            vpt.Init(wVec);
            segment.InitFromOriginAndDirection(pt, vpt);
    
            ICurvePrimitivePtr lineString = ICurvePrimitive::CreateLine(segment);
    
    
            EditElementHandle eehSub3;
            DraftingElementSchema::ToElement(eehSub3, *lineString, nullptr, ACTIVEMODEL->Is3d(), *ACTIVEMODEL);
            eehSub3.AddToModel();
            /////////////////////////////////////////////////////////////////////////////////////////////////
    
            yVec.Init(0.0, 0.0, 1.0);
            xVec = DVec3d::FromCrossProduct(yVec, zVec);
            xVec.Normalize();
    
            yVec = DVec3d::FromCrossProduct(zVec, xVec);
    
            xVec.Normalize();
            yVec.Normalize();
            zVec.Normalize();
    
            rMatrix = RotMatrix::FromColumnVectors(xVec, yVec, zVec);
            Transform  vecTransform = Transform::From(rMatrix, pt);
    
    
            curVec2->TransformInPlace(vecTransform);
    
            profiles.push_back(curVec2);
    
            EditElementHandle eehSub1;
            DraftingElementSchema::ToElement(eehSub1, *curVec2, nullptr, ACTIVEMODEL->Is3d(), *ACTIVEMODEL);
            eehSub1.AddToModel();
        }
    
        ISolidKernelEntityPtr body;
        if (SUCCESS != SolidUtil::Create::BodyFromLoft(body, &profiles.front(), profiles.size(), &path, 1, *ACTIVEMODEL))
        {
            return ERROR;
        }
    
        if (body == nullptr)
            return ERROR;
    
        EditElementHandle sweepEh;
        BentleyStatus nStatus = SolidUtil::Convert::BodyToElement(sweepEh, *body.get(), nullptr, *ACTIVEMODEL);
        if (BentleyStatus::SUCCESS == nStatus)
        {
            sweepEh.AddToModel();
        }
    }

  • 谢谢老师,但是 我并没有  使用ord,第二 根据 我的理解  是可以相切的, 因为这三个截面 中心点 在一条Z轴线上,另外 三个截面 互信平行!导向线  是 每一个 截面的 左下角顶点 相连  ,形成的两条导向线。

    辛苦老师 帮忙在分析一下!!!!

    Bentley 二次开发小白一枚

  • 不传递guides可以生成:

    void createLoftSolid(DPoint3dR basePt)
    {
    	//数据准备阶段
    	int x1 = 150, x2 = 3650, x3 = 100, x4 = 2200, x5 = 100, x6 = 3650, x7 = 150;
    	int y1 = 300, y2 = 2400, y3 = 300;
    	int x1Len = x1 + x2 + x3 + x4 + x5 + x6 + x7;
    	int y1Len = y1 + y2 + y3;
    	//int nKouCaoy=100;
    	//int nKouCaox=400;
    	//int nKouCaoDx=350;
    	int nHigthZ1 = 800;
    	int nHigthZ2 = 900;
    	//int nradius=50;
    
    	//构建放样的导向线
    	DPoint3d Pts[3];
    	Pts[0].x = basePt.x - x4 / 2; 			Pts[0].y = basePt.y - y2 / 2; 		Pts[0].z = basePt.z;
    	Pts[1].x = basePt.x - x4 / 2 - x3 - x2 - x1;  Pts[1].y = basePt.y - y1Len / 2; 	Pts[1].z = basePt.z + nHigthZ1;
    	Pts[2].x = basePt.x - x1Len / 2 + x1;  	Pts[2].y = basePt.y - y2 / 2; 		Pts[2].z = basePt.z + nHigthZ1 + nHigthZ2;
    	/***********************************************************************************************************/
    	 // 2 ---- 创建 CurveVectorPtr 数组 存储 CurveVector,并将两个圆
    	CurveVectorPtr profileVec[3];
    	//BOUNDARY_TYPE_Outer is important, it can create a closed profile that further makes a solid instead of a sheet
    	profileVec[0] = CurveVector::Create(CurveVector::BOUNDARY_TYPE_Outer);
    	profileVec[0]->Add(ICurvePrimitive::CreateRectangle(basePt.x - x4 / 2, basePt.y - y2 / 2, basePt.x + x4 / 2, basePt.y + y2 / 2, basePt.z));//最下面的矩形 也是最小的
    	 
    	profileVec[1] = CurveVector::Create(CurveVector::BOUNDARY_TYPE_Outer);
    	profileVec[1]->Add(ICurvePrimitive::CreateRectangle(basePt.x - x1Len / 2, basePt.y - y1Len / 2, basePt.x + x1Len / 2, basePt.y + y1Len / 2, basePt.z + nHigthZ1));//中间的矩形,也是最大的矩形
    	 
    	profileVec[2] = CurveVector::Create(CurveVector::BOUNDARY_TYPE_Outer);
    	profileVec[2]->Add(ICurvePrimitive::CreateRectangle(basePt.x - x1Len / 2 + x1, basePt.y - y2 / 2, basePt.x + x1Len / 2 - x1, basePt.y + y2 / 2, basePt.z + nHigthZ1 + nHigthZ2));//最上面的矩形,
    	 
    	DSegment3d seg;
    	seg.Init(Pts[0], Pts[1]);
    	//CurveVectorPtr guideVec[2];
    	//guideVec[0] = CurveVector::Create(CurveVector::BOUNDARY_TYPE_Open);
    	//guideVec[1] = CurveVector::Create(CurveVector::BOUNDARY_TYPE_Open);
    	//guideVec[0]->Add(ICurvePrimitive::CreateLine(seg));//最下面和中间 两个矩形的连接线 也就是向导线
    	//seg.Init(Pts[1], Pts[2]);
    	//guideVec[1]->Add(ICurvePrimitive::CreateLine(seg));//中间和最上面 两个矩形的连接线 也就是向导线
    
    		//改成一个向导线 也不行。如下
    		CurveVectorPtr guideVec;
    		guideVec= CurveVector::Create(CurveVector::BOUNDARY_TYPE_Open);
    		guideVec->Add(ICurvePrimitive::CreateLineString(Pts , 3)); 
    		
    
    
    		// 3 ---- Create Solid by Loft
    	ISolidKernelEntityPtr solid;
    	DgnModelP             pActiveModel = ISessionMgr::GetActiveDgnModelP();
    	//if (SUCCESS != SolidUtil::Create::BodyFromLoft(solid, profileVec, 3, &guideVec, 1, *pActiveModel, false, true))
    	if (SUCCESS != SolidUtil::Create::BodyFromLoft(solid, profileVec, 3, NULL, 0, *pActiveModel, false, true))
    	{
    		mdlDialog_dmsgsPrint(L"Error in BodyFromLoft");
    		return;
    	}
    
    	// 4 ---- Convert Solid to EditElementHandle and add it to model
    	if (solid.IsValid())
    	{
    		EditElementHandle eeh;
    		SolidUtil::Convert::BodyToElement(eeh, *solid, nullptr, *pActiveModel);
    		//DraftingElementSchema::ToElement(eeh, *solid, nullptr, *pActiveModel);
    		eeh.AddToModel();
    	}
    
    }

    Answer Verified By: 平凡人生 

  • 郭老师:

            您好,按照您说的 确实 ,已经可以了,但是针对  BodyFromLoft   还是有一些不明所以,肯请解释 说明。

    1、导向线不也是和 截面 一样,是一个数组吗?什么情况下可以使用该数组?

    2、我的情况是否满足使用导向线数组的情况,如果满足,应该怎么使用(比如我题中 三个截面,两个导向线)?

    3、使用一根导向线的话,就向您帮我解决的这个问题(三个截面,使用一个导向线)是否有需要注意的地方或限制条件?

    4、我的这个情况,不向BodyFromLoft    传入导向线 ,就可以成功 ,是什么原因?

     辛苦老师,给予解答!!!!多谢!!!!

    Bentley 二次开发小白一枚

  • 这种通过面、轮廓、路径构造体的方法是不能保证一定能生成的,因为通过输入这些参数去构造体的时候有可能会出现非法体(例如自交)的情况,具体是什么原因造成的,这得非常熟悉loft(还有一种跟loft比较类似的sweep)的底层算法才能分析出来。其实有些情况下我们是不用调用这些函数去构造我们的体的,例如如果想生成个正四面体的话,您可能会为了省事,构造四个正三角形,然后调用缝合的函数去构造这个四面体。这种情况,其实完全可以通过先生成一个立方体,然后去构造负实体,从这个立方体上切割出一个正四面体出来。所以我的建议是,编程的时候如果能不使用就不要使用这些sweep、loft、缝合等这些函数,通过构造负实体从大的体上切割出来自己想要的实体。