前言
这个例子模拟光线反弹。
内容
通过修改参数,从(0,0,0)点向(1,0,0)方向射出光线,经过若干次反弹之后的结果。如图所示:
在Revit API 中,用 ReferenceIntersector::Find 来计算射线上相交的几何。
核心逻辑,简化了代码,只保留重要部分:
// 从起点 startpt 出发,做 rayLimit 次射线
Autodesk.Revit.DB.XYZ startpt = m_origin;
for (int ctr = 1; ctr <= rayLimit; ctr++){
// 通过 ReferenceIntersector::Find 查找相交几何
ReferenceIntersector referenceIntersector = new ReferenceIntersector(m_view);
IList<ReferenceWithContext> references = referenceIntersector.Find(startpt, m_direction);
m_rClosest = null;
// 遍历找到最近的几何,获取相交点
FindClosestReference(references);
Reference reference = m_rClosest.GetReference();
Element referenceElement = m_doc.GetElement(reference);
GeometryObject referenceObject = referenceElement.GetGeometryObjectFromReference(reference);
Autodesk.Revit.DB.XYZ endpt = reference.GlobalPoint;
// 绘制一条线段表示光线
MakeLine(startpt, endpt, m_direction, "bounce");
// 计算反射光线的防线
m_face = referenceObject as Face;
Autodesk.Revit.DB.UV endptUV = reference.UVPoint;
Autodesk.Revit.DB.XYZ FaceNormal = m_face.ComputeDerivatives(endptUV).BasisZ; // face normal where ray hits
FaceNormal = m_rClosest.GetInstanceTransform().OfVector(FaceNormal); // transformation to get it in terms of document coordinates instead of the parent symbol
Autodesk.Revit.DB.XYZ directionMirrored = m_direction - 2 * m_direction.DotProduct(FaceNormal) * FaceNormal; //http://www.fvastro.org/presentations/ray_tracing.htm
m_direction = directionMirrored; // get ready to shoot the next ray
// 重置光线起点
startpt = endpt;
}
FindClosetReference 核心逻辑:
double face_prox = Double.PositiveInfinity;
double edge_prox = Double.PositiveInfinity;
foreach (ReferenceWithContext r in references){
Reference reference = r.GetReference();
Element referenceElement = m_doc.GetElement(reference);
GeometryObject referenceGeometryObject = referenceElement.GetGeometryObjectFromReference(reference);
m_face = null;
m_face = referenceGeometryObject as Face;
Edge edge = null;
edge = referenceGeometryObject as Edge;
if (m_face != null){
if ((r.Proximity < face_prox) && (r.Proximity > epsilon)){
m_rClosest = r;
face_prox = Math.Abs(r.Proximity);
}
}
}