我有一个非常“基于连接”的应用程序,即多个输入/输出。
我正在寻找“电缆”的UI概念,以使该概念对用户清晰可见。 Propellerhead在其Reason软件中采用了类似的方法来处理音频组件,如this YouTube video (fast forward to 2m:50s)所示。
我可以通过绘制从A点到B点的样条曲线来在GDI中实现这一概念,必须有一种更为优雅的方法来使用Paths或WPF中的某些东西,但是从哪里开始呢?捕获并摇晃电缆摆动时,是否有一种很好的方法来模拟电缆摆动的动画?
如果已经为WPF发明了这种轮子,我也愿意控制库(商业或开源)。
更新:由于到目前为止答案中的链接,我快到了。
我已经以编程方式创建了一个BezierCurve
,其中Point 1是(0, 0)
,Point 2是底部的“悬挂”点,Point 3是鼠标光标所在的位置。我为Point 2创建了一个PointAnimation
,并对其应用了ElasticEase
缓动函数以提供“摇摆”效果(即,将中间点弹起一点)。
唯一的问题是,动画似乎播放得有点晚。每当鼠标移动时,我都会启动 Storyboard ,是否有更好的方法来制作此动画?到目前为止,我的解决方案位于:
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);
}
最佳答案
如果要进行真正的动态运动(即,当您“摇动”鼠标指针时,您可以创建沿绳索传播的波浪),则需要使用有限元技术。但是,如果您对静态行为没问题,则可以简单地使用Bezier曲线。
首先,我将简要描述有限元方法,然后再详细介绍静态方法。
动态方法
将您的“绳索”划分为大量(大约1000个)“元素”,每个元素都有一个位置和速度 vector 。使用CompositionTarget.Rendering事件来计算每个元素的位置,如下所示:
静态方法
将您的绳索分成大约30个部分,每个部分近似于悬链线y = a cosh(x / a)的立方贝塞尔曲线。您的最终控制点应在悬链线上,平行线应与悬链线相切,并且控制线的长度应基于悬链线的二阶导数设置。
在这种情况下,您可能还希望使用BeginFigure和PolyBezierTo来构建StreamGeometry。
我将其实现为类似于Rectangle和Ellipse的自定义Shape子类“Catenary”。在这种情况下,您只需要重写DefiningGeometry属性即可。为了提高效率,我还将覆盖CacheDefiningGeometry,GetDefiningGeometryBounds和GetNaturalSize。
您将首先决定如何参数化悬链线,然后为所有参数添加DependencyProperties。确保在FrameworkPropertyMetadata中设置AffectsMeasure和AffectsRender标志。
一种可能的参数化是XOffset,YOffset,Length。另一个可能是XOffset,YOffset,SagRelativeToWidth。这将取决于最容易绑定(bind)的内容。
定义DependencyProperty后,实现DefiningGeometry属性以计算三次贝塞尔曲线控制点,构造StreamGeometry并返回它。
如果执行此操作,则可以将“悬链线”控件放在任何位置,并获得悬链线曲线。
关于c# - 如何在WPF中模拟悬挂式电缆?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4206983/