【问题标题】:How can I simulate a hanging cable in WPF?如何在 WPF 中模拟悬挂电缆?
【发布时间】:2010-11-17 16:57:27
【问题描述】:

我有一个非常“基于连接”的应用程序,即多个输入/输出。

“电缆”的 UI 概念正是我想要让用户清楚了解的概念。 Propellerhead 在其用于音频组件的 Reason 软件中采用了类似的方法,如 this YouTube video (fast forward to 2m:50s) 所示。

我可以通过绘制从 A 点到 B 点的样条线来使这个概念在 GDI 中发挥作用,必须有一种更优雅的方式来使用 WPF 中的路径或其他东西,但是你从哪里开始呢?有没有什么好的方法可以模拟绳索摇晃时的动画?

如果这个轮子已经为 WPF 发明了,我也愿意控制库(商业或开源)。

更新:感谢到目前为止答案中的链接,我快到了。

我以编程方式创建了一个BezierCurve,点 1 是 (0, 0),点 2 是底部“挂起”点,点 3 是鼠标光标所在的位置。我为第 2 点创建了一个PointAnimation,并对其应用了一个ElasticEase 缓动函数以提供“摇摆”效果(即,使中间点稍微弹跳)。

唯一的问题是,动画似乎有点晚了。每次鼠标移动时我都会启动情节提要,有没有更好的方法来制作这个动画?到目前为止,我的解决方案位于此处:

Bezier Curve Playground

代码:

private Path _path = null;
private BezierSegment _bs = null;
private PathFigure _pFigure = null;
private Storyboard _sb = null;
private PointAnimation _paPoint2 = null;
ElasticEase _eEase = null;

private void cvCanvas_MouseMove(object sender, MouseEventArgs e)
{
    var position = e.GetPosition(cvCanvas);
    AdjustPath(position.X, position.Y);
}

// basic idea: when mouse moves, call AdjustPath and draw line from (0,0) to mouse position with a "hang" in the middle
private void AdjustPath(double x, double y)
{
    if (_path == null)
    {
        _path = new Path();
        _path.Stroke = new SolidColorBrush(Colors.Blue);
        _path.StrokeThickness = 2;
        cvCanvas.Children.Add(_path);

        _bs = new BezierSegment(new Point(0, 0), new Point(0, 0), new Point(0, 0), true);

        PathSegmentCollection psCollection = new PathSegmentCollection();
        psCollection.Add(_bs);

        _pFigure = new PathFigure();
        _pFigure.Segments = psCollection;
        _pFigure.StartPoint = new Point(0, 0);


        PathFigureCollection pfCollection = new PathFigureCollection();
        pfCollection.Add(_pFigure);

        PathGeometry pathGeometry = new PathGeometry();
        pathGeometry.Figures = pfCollection;

        _path.Data = pathGeometry;
    }

    double bottomOfCurveX = ((x / 2));
    double bottomOfCurveY = (y + (x * 1.25));

    _bs.Point3 = new Point(x, y);

    if (_sb == null)
    {
        _paPoint2 = new PointAnimation();

        _paPoint2.From = _bs.Point2;
        _paPoint2.To = new Point(bottomOfCurveX, bottomOfCurveY);
        _paPoint2.Duration = new Duration(TimeSpan.FromMilliseconds(1000));
        _eEase = new ElasticEase();

        _paPoint2.EasingFunction = _eEase;
        _sb = new Storyboard();

        Storyboard.SetTarget(_paPoint2, _path);
        Storyboard.SetTargetProperty(_paPoint2, new PropertyPath("Data.Figures[0].Segments[0].Point2"));

        _sb.Children.Add(_paPoint2);
        _sb.Begin(this);                
    }

    _paPoint2.From = _bs.Point2;
    _paPoint2.To = new Point(bottomOfCurveX, bottomOfCurveY);

    _sb.Begin(this);
}

【问题讨论】:

标签: c# wpf silverlight graphics gdi+


【解决方案1】:

如果您想要真正的动态运动(即,当您“摇动”鼠标指针时,您可以创建沿着绳索传播的波),您将需要使用有限元技术。但是,如果您对静态行为没问题,您可以简单地使用贝塞尔曲线。

首先我将简要介绍有限元方法,然后详细介绍静态方法。

动态方法

将你的“绳索”分成大量(1000 个左右)“元素”,每个元素都有一个位置和速度向量。使用 CompositionTarget.Rendering 事件计算每个元素的位置,如下所示:

  • 计算相邻元素沿“绳索”对每个元素的拉力,该拉力与元素之间的距离成正比。假设绳索本身是无质量的。

  • 计算每个“元素”上的净力矢量,其中包括沿绳索的每个相邻元素的拉力,加上恒定的重力。

  • 使用质量常数将力矢量转换为加速度,并使用运动方程更新位置和速度。

  • 使用带有 BeginFigure 和 PolyLineTo 的 StreamGeometry 构建来绘制线。有了这么多点,几乎没有理由进行额外的计算来创建三次贝塞尔近似。

静态方法

将您的绳索分成大约 30 段,每段是悬链线 y = a cosh(x/a) 的三次贝塞尔曲线近似值。您的终点控制点应位于悬链线曲线上,平行线应与悬链线相切,并且控制线长度应基于悬链线的二阶导数设置。

在这种情况下,您可能还想渲染一个 StreamGeometry,使用 BeginFigure 和 PolyBezierTo 来构建它。

我会将其实现为类似于 Rectangle 和 Ellipse 的自定义 Shape 子类“悬链线”。在这种情况下,您必须重写 DefiningGeometry 属性。为了提高效率,我还会覆盖 CacheDefiningGeometry、GetDefiningGeometryBounds 和 GetNaturalSize。

您将首先决定如何参数化悬链线,然后为所有参数添加 DependencyProperties。确保在 FrameworkPropertyMetadata 中设置了 AffectsMeasure 和 AffectsRender 标志。

一种可能的参数化是 XOffset、YOffset、Length。另一个可能是 XOffset、YOffset、SagRelativeToWidth。这取决于最容易绑定的内容。

定义完 DependencyProperties 后,实现 DefiningGeometry 属性以计算三次贝塞尔控制点,构造 StreamGeometry 并将其返回。

如果您这样做,您可以将悬链线控件放在任何地方并获得悬链线曲线。

【讨论】:

    【解决方案2】:

    【讨论】:

    • Guy:他想要一种特定的曲线,而不仅仅是任何曲线。
    • @Gabe,@Guy,这看起来像是一种可行的技术(我可以在基本路径工作后使用曲线),现在正在寻找如何以编程方式而不是在XAML..
    【解决方案3】:

    恕我直言,“悬挂”(物理模拟)电缆是过度使用的一种情况 - 注重外观而不是可用性。

    你确定你不只是弄乱用户体验吗?

    在基于节点/连接的 UI 中,我发现 clear 连接(如在 Quartz Composer 中:http://ellington.tvu.ac.uk/ma/wp-content/uploads/2006/05/images/Quartz%20Composer_screenshot_011.png)比像摆动电缆那样朝不同方向(向下由于重力)而不是实际连接点的位置。 (同时消耗 CPU 周期进行模拟,这可能在其他地方更有用)

    只要我的 0.02 美元

    【讨论】:

    • 我确实明白你在说什么,但 IMO 总是值得在与你的概念完全一致的 UI 上冒险。电缆立即传达了这一概念;也许类似 Quartz 的视图会成为一个很好的替代视图。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-11
    • 2013-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多