OpenCasCad 之鼠标点选,抓取曲线上任意一点的计算

疫情静态管控在家,花费一周琢磨出这么点东西,分享一下。

难点是理解Visualization中V3d中的V3d_View类的使用。

在大神的帮助下,我解了这个问题。

我的投影是Ortho,工业制图,都是简单的这种。

代码如下,仅供参考:

void GetWorldPt(double x,double y)
{
    //点选元素,只接受线
    TopTools_IndexedMapOfShape aEdgeMap;
    for(myAISContext->InitSelected();myAISContext->MoreSelected();myAISContext->NextSelected()) 
    {
        TopoDS_Shape aSelShape = myAISContext->SelectedShape();
        if(aSelShape.IsNull())
            continue;
        TopAbs_ShapeEnum aShapeType = aSelShape1.ShapeType();
        if(aShapeType == TopAbs_EDGE)
        {   
            TopoDS_Edge  aEdge =  TopoDS::Edge(aSelShape);
            aEdgeMap.Add(aEdge);            
            break;//实验只接受一条线
        }
    }
    if(aEdgeMap.Size() <= 0)
      return;

    Standard_Real viewWidth, viewHeight;
    myView->Size (viewWidth, viewHeight) ;
 
    Standard_Real XEye,YEye,ZEye,XAt,YAt,ZAt;
    myView->Eye(XEye,YEye,ZEye);
    myView->At(XAt,YAt,ZAt);

    gp_Pnt EyePoint(XEye,YEye,ZEye);
    gp_Pnt AtPoint(XAt,YAt,ZAt);

    gp_Vec EyeVector(EyePoint,AtPoint);
    gp_Dir EyeDir(EyeVector);

    //构建view at 面
    gp_Pln PlaneOfTheView = gp_Pln(AtPoint,EyeDir);

    //从pixel转化为wcs空间
    Standard_Real Xt,Yt,Zt;
    myView->Convert(int(x),int(Y),Xt,Yt,Zt);
    //绘制出来
    gp_Pnt ConvertedPoint(Xt,Yt,Zt);
    TCollection_AsciiString TheStringConvertedPoint ("ConvertedPoint");
    DisplayPoint(ConvertedPoint,Quantity_NOC_BROWN4,TheStringConvertedPoint.ToCString(),true);

    //投影到view at 面的2D点
    gp_Pnt2d ConvertedPointOnPlane = ProjLib::Project(PlaneOfTheView,ConvertedPoint);
    //在view at 面的3D点
    gp_Pnt ResultPoint = ElSLib::Value(ConvertedPointOnPlane.X(),ConvertedPointOnPlane.Y(),PlaneOfTheView);
    //绘制出来
    TCollection_AsciiString TheStringResultPoint ("ResultPoint");
    DisplayPoint(ResultPoint,Quantity_NOC_BROWN4,TheStringResultPoint.ToCString(),true);

    //绘制view at 面出来
    BRepBuilderAPI_MakeFace aMakeFace(PlaneOfTheView,-viewWidth*0.5,viewWidth*0.5,-viewWidth*0.5,viewWidth*0.5);
    Handle(AIS_Shape)    XFace = new AIS_Shape(aMakeFace.Face ());
    myAISContext->SetColor(XFace, Quantity_NOC_MAGENTA1, Standard_False);
     myAISContext->Display (XFace,0, -1, Standard_False);
     myAISContext->SetDisplayMode (XFace,AIS_WireFrame, Standard_False);

    //绘制Pick line出来,是和view at 面垂直,且通过ConvertedPoint,ConvertedPointMirror 两个点的线
    gp_Pnt ConvertedPointMirror = ConvertedPoint.Mirrored(ResultPoint); 
    Handle(Geom_Line) Line = new Geom_Line(ConvertedPoint,EyeDir);
    BRepBuilderAPI_MakeEdge aMakeEdge(Line,ConvertedPoint,ConvertedPointMirror);//镜像点是为了线能穿透投影面
    TopoDS_Edge aPickEdge =  aMakeEdge.Edge ();
    Handle(AIS_Shape)    XEdge = new AIS_Shape(aPickEdge);
    myAISContext->SetColor(XEdge, Quantity_NOC_MAGENTA1, Standard_False);
     myAISContext->Display (XEdge,0, -1, Standard_False);

    //用于后面最PickCurve线Select线相交做准备
    BRepAdaptor_Curve aPickCurve(aPickEdge);

    double minDist = 1000000;
    gp_Pnt minPt;
    for (Standard_Integer k=1;k<=edgemap.Extent();k++)
    {
        TopoDS_Edge aSelectEdge = TopoDS::Edge(edgemap(k));
        //Select线
        BRepAdaptor_Curve aSelectCurve(aSelectEdge);
        //相交
        Extrema_ExtCC aExtCC(aSelectCurve, aPickCurve);
        int Nb = aExtCC.NbExt();
        for (int NoSol=1; NoSol<= Nb; ++NoSol) 
        {
            //得到距离
            Standard_Real dist = aExtCC.SquareDistance (NoSol);
            if(minDist >= dist)
            {
                Extrema_POnCurv P1,  P2;
                //得到两条线上的点
                aExtCC.Points (NoSol, P1,  P2);
                minDist = dist;
                //把select线转化为gp_Pnt                
                minPt = P1.Value();
            }
        }
    }
    if(minDist < 1000000)
    {
        //绘制交点
        TCollection_AsciiString TheString ("cross");
        DisplayPoint(minPt,Quantity_NOC_BROWN4,TheString.ToCString(),true);
    }
}

备注:

Extrema_ExtCC 这个源码需要细致琢磨,它对于交点超出某个curve长度的范围计算就不对了,确切说不是我们想要的,要仔细设定pick直线的长度,确保抓到想要的交点。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值