如何检测贝塞尔曲线是否与指定的椭圆相交?

How to detect, if a bezier curve intersects a specified ellipse?

我有一个自定义控件,它呈现一条从左上角到右下角的贝塞尔曲线。我想修改命中测试行为,以便控件仅在悬停在贝塞尔曲线上方或附近时才“命中”,但 FillContainsWithDetail 没有 return 预期结果。

我错过了什么?

这是一个派生的例子class:

public class BezierControl : FrameworkElement
{
    protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
    {
        if (_geometry == null) return null;
        
        var p = hitTestParameters.HitPoint;

        EllipseGeometry expandedHitTestArea = new EllipseGeometry(p, 10.0, 10.0);
        
        var intersection = expandedHitTestArea.FillContainsWithDetail(_geometry);
        if (intersection > IntersectionDetail.Empty)
        {
            return new PointHitTestResult(this, hitTestParameters.HitPoint);
        }

        return null;
    }

    private StreamGeometry _geometry;

    private StreamGeometry getGeometry()
    {
        var result = new StreamGeometry();

         
            using (var context = result.Open())
            {
                var start = new Point(0, 0);
                var startCp = new Point(10, 0);
                var end = new Point(this.ActualWidth, this.ActualHeight);
                var endCp = new Point(this.ActualWidth - 10, this.ActualHeight);

                context.BeginFigure(start, false, false);
                context.BezierTo(startCp, endCp, end, true, false);
            }
     

        result.Freeze();

        return result;
    }
    
    
    protected override void OnRender(DrawingContext dc)
    {
        base.OnRender(dc);

        if (_geometry == null) _geometry = getGeometry();

        dc.DrawGeometry(null, _pen, _geometry);
    }

    private Pen _pen = new Pen(Brushes.Red, 1.0);

}

编辑:下面批准的答案很好,但它也让我想到了另一个选择——或者告诉我为什么我尝试的解决方案失败了:我正在创建这样的几何体:

context.BeginFigure(bezier.Start, false, false);

第一个 bool 参数称为 isFilled。将此设置为 true 允许在 _geometryexpandedHitTestArea 之间相交。

在注意到这一点之前,我实施了下面接受的答案,并出于性能原因决定延迟创建 widenedGeometry。现在我想知道:从性能的角度来看,哪种方法更好?或者,在这种情况下这可以忽略不计,因为几何图形无论如何都不贵?

您不需要那个 EllipseGeometry。只需检查命中点是否在原始几何体的加宽路径几何体内(当然也可以在创建_geometry时创建一次):

protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters)
{
    if (_geometry != null)
    {
        var widenedGeometry = _geometry.GetWidenedPathGeometry(new Pen(null, 20));

        if (widenedGeometry.FillContains(hitTestParameters.HitPoint))
        {
            return new PointHitTestResult(this, hitTestParameters.HitPoint);
        }
    }

    return null;
}