// alternative way, 3.36 times slower protected bool MyHitTest(Ray rayWS, ref List<HitTestResult> hits) { LineGeometry3D lineGeometry3D; Viewport3DX viewport; if (this.Visibility == Visibility.Collapsed || this.IsHitTestVisible == false || (viewport = FindVisualAncestor<Viewport3DX>(this.renderHost as DependencyObject)) == null || (lineGeometry3D = this.Geometry as LineGeometry3D) == null) { return false; } var result = new HitTestResult { IsValid = false, Distance = double.MaxValue }; var lastDist = double.MaxValue; var index = 0; foreach (var line in lineGeometry3D.Lines) { var t0 = Vector3.TransformCoordinate(line.P0, this.ModelMatrix); var t1 = Vector3.TransformCoordinate(line.P1, this.ModelMatrix); Vector3 sp, tp; float sc, tc; var distance = LineBuilder.GetRayToLineDistance(rayWS, t0, t1, out sp, out tp, out sc, out tc); var svpm = viewport.GetScreenViewProjectionMatrix(); Vector4 sp4; Vector4 tp4; Vector3.Transform(ref sp, ref svpm, out sp4); Vector3.Transform(ref tp, ref svpm, out tp4); var sp3 = sp4.ToVector3(); var tp3 = tp4.ToVector3(); var tv2 = new Vector2(tp3.X - sp3.X, tp3.Y - sp3.Y); var dist = tv2.Length(); if (dist < lastDist && dist <= this.HitTestThickness) { lastDist = dist; result.PointHit = sp.ToPoint3D(); result.NormalAtHit = (sp - tp).ToVector3D(); // not normalized to get length result.Distance = distance; result.ModelHit = this; result.IsValid = true; result.Tag = index; // ToDo: LineHitTag with additional info } index++; } if (result.IsValid) { hits.Add(result); } return result.IsValid; }
public override bool HitTest(Ray rayWS, ref List<HitTestResult> hits) { LineGeometry3D lineGeometry3D; Viewport3DX viewport; if (this.Visibility == Visibility.Collapsed || this.IsHitTestVisible == false || (viewport = FindVisualAncestor<Viewport3DX>(this.renderHost as DependencyObject)) == null || (lineGeometry3D = this.Geometry as LineGeometry3D) == null) { return false; } // revert unprojection; probably better: overloaded HitTest() for LineGeometryModel3D? var svpm = viewport.GetScreenViewProjectionMatrix(); var smvpm = this.modelMatrix * svpm; var clickPoint4 = new Vector4(rayWS.Position + rayWS.Direction, 1); Vector4.Transform(ref clickPoint4, ref svpm, out clickPoint4); var clickPoint = clickPoint4.ToVector3(); var result = new HitTestResult { IsValid = false, Distance = double.MaxValue }; var maxDist = this.HitTestThickness; var lastDist = double.MaxValue; var index = 0; foreach (var line in lineGeometry3D.Lines) { var p0 = Vector3.TransformCoordinate(line.P0, smvpm); var p1 = Vector3.TransformCoordinate(line.P1, smvpm); Vector3 hitPoint; float t; var dist = LineBuilder.GetPointToLineDistance2D(ref clickPoint, ref p0, ref p1, out hitPoint, out t); if (dist < lastDist && dist <= maxDist) { lastDist = dist; Vector4 res; var lp0 = line.P0; Vector3.Transform(ref lp0, ref this.modelMatrix, out res); lp0 = res.ToVector3(); var lp1 = line.P1; Vector3.Transform(ref lp1, ref this.modelMatrix, out res); lp1 = res.ToVector3(); var lv = lp1 - lp0; var hitPointWS = lp0 + lv * t; result.Distance = (rayWS.Position - hitPointWS).Length(); result.PointHit = hitPointWS.ToPoint3D(); result.ModelHit = this; result.IsValid = true; result.Tag = index; // ToDo: LineHitTag with additional info } index++; } if (result.IsValid) { hits.Add(result); } return result.IsValid; }