// 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;
        }