2016-08-23 259 views
0

我與螺旋工具庫的sharpDX分支的一個項目,在我的大學工作(HelixToolKit Library如何在helix-toolkit sharpDX視口中選擇最頂層的元素?

目前我正在尋找一種方法來正確地選擇在視口中的元素。

我發現了一個有用的例子在helixtoolkit庫的源代碼:example code on GitHub

public class MyLineGeometryModel3D : LineGeometryModel3D 
{ 
    private Color? initialColor = null; 

    public override bool HitTest(Ray rayWS, ref List<HitTestResult> hits) 
    { 
     if (initialColor == null) 
     { 
      initialColor = this.Color; 
     } 

     var result = base.HitTest(rayWS, ref hits); 
     var pressedMouseButtons = Viewport3DX.GetPressedMouseButtons(); 

     if (pressedMouseButtons == 0 || pressedMouseButtons.HasFlag(MouseButtons.Left)) 
     { 
      this.Color = result ? Color.Red : this.initialColor.Value; 
     } 
     return result; 
    } 

}

我設法在我的應用程序得到這個運行。然而,不是隻選擇最上面的元素,而是選擇與光線相交的所有元素。 某些類型的處理函數可能需要突出顯示最短距離的元素?

我正在檢查一些標準的WPF解決方案,他們經常使用事件處理程序。 (例如3D Hit Testing in WPF

private void m_viewport3d_MouseDown(object sender, MouseButtonEventArgs e) 
{ 
    Point mousePos = e.GetPosition(m_viewport3d); 
    PointHitTestParameters hitParams = new PointHitTestParameters(mousePos); 
    HitTestResult result = VisualTreeHelper.HitTest(m_viewport3d, mousePos); 
    RayMeshGeometry3DHitTestResult rayMeshResult = result as RayMeshGeometry3DHitTestResult; 
    if (rayMeshResult != null) 
    { 
     MeshGeometry3D mesh = new MeshGeometry3D(); 
     mesh.Positions.Add(rayMeshResult.MeshHit.Positions[rayMeshResult.VertexIndex1]); 
     mesh.Positions.Add(rayMeshResult.MeshHit.Positions[rayMeshResult.VertexIndex2]); 
     mesh.Positions.Add(rayMeshResult.MeshHit.Positions[rayMeshResult.VertexIndex3]); 
     mesh.TriangleIndices.Add(0); 
     mesh.TriangleIndices.Add(1); 
     mesh.TriangleIndices.Add(2); 
     GeometryModel3D marker = new GeometryModel3D(mesh, new DiffuseMaterial(Brushes.Blue)); 
     //...add marker to the scene... 
    } 
} 

使用事件處理程序是一個合理的解決方案嗎?如果是的話,如何獲得一個用於在事件處理程序中調用HitTest函數的ray元素?

回答

1

使用視方法FindNearest:

private void OnMouseDown(object sender, MouseButtonEventArgs e) 
{  
    Viewport3DX vp = e.Source as Viewport3DX; 

    Point3D p; 
    Vector3D v; 
    Model3D m; 
    if (vp.FindNearest(e.GetPosition(vp), out p, out v, out m)) 
    { 
     //Do something with the found object 
    } 
} 
+0

謝謝你的幫助。我嘗試了您的解決方案,但它對我無效,因爲我需要更改Model3D類中尚未包含的模型的材質。也許有一個解決方法,我不知道:-)但我實際上自己找到了一個解決方案(下面發佈) – Daniel

0

所以,我居然找到了自己的解決方案,這可能是不完美的。但也許這對某個人來說是有用的。

 private void ViewPort3D_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) 
     { 

      Ray ray = this.ViewPort3D.UnProject(new Vector2((float)e.GetPosition(ViewPort3D).X, (float)e.GetPosition(ViewPort3D).Y)); 
      var hits = new List<HitTestResult>(); 

      // dictionary for connecting the id of the specific element and its distance 
      var hitElements = new Dictionary<int, double>(); 

      // loop over all MeshGeometryModel3D elements 
      foreach (var geometry in Geometrys) 
      { 
       var isHit = geometry.Model3D.HitTest(ray, ref hits); 
       if (isHit) 
       { 
        hitElements.Add(geometry.Id, hits[hits.Count - 1].Distance); 
       } 
      } 

      if (hits.Count > 0) 
      { 

       double minDistance = hitElements.First().Value; 
       int id_of_hit_element = hitElements.First().Key; 

       foreach (var hit in hitElements) 
       { 
        if (hit.Value < minDistance) 
        { 
         minDistance = hit.Value; 
         id_of_hit_element = hit.Key; 
        } 
       } 

       var topElement = Geometrys.Find(geometry => geometry.Id == id_of_hit_element); 

       // do something with top element 
      } 
     } 

P.S.不是計算機科學家btw,只是一個土木工程學生嘗試他最好的xD