疫情静态管控在家,花费一周琢磨出这么点东西,分享一下。
难点是理解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直线的长度,确保抓到想要的交点。