Wpf自定义LineArrow形状旋转

时间:2016-02-24 11:01:13

标签: wpf rotation shape

以下代码允许我用箭头画一条线:

public sealed class LineArrow : Shape
{
    #region X1
    public double X1
    {
        get { return (double)GetValue( X1Property ); }
        set { SetValue( X1Property, value ); }
    }

    // Using a DependencyProperty as the backing store for X1.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty X1Property =
        DependencyProperty.Register( "X1", typeof( double ), typeof( LineArrow ), new FrameworkPropertyMetadata( 0.0,
                FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure ) ); 
    #endregion

    #region Y1
    public double Y1
    {
        get { return (double)GetValue( Y1Property ); }
        set { SetValue( Y1Property, value ); }
    }

    // Using a DependencyProperty as the backing store for Y1.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty Y1Property =
        DependencyProperty.Register( "Y1", typeof( double ), typeof( LineArrow ), new FrameworkPropertyMetadata( 
            0.0, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure ) );
    #endregion

    protected override Geometry DefiningGeometry
    {
        get
        {
            var lineStart = new Point( X1, Y1 );
            var lineEnd = new Point( this.ActualWidth, this.ActualHeight );
            var lineAngle = Math.Atan2( this.ActualHeight, this.ActualWidth );

            RotateTransform rotation = new RotateTransform() { Angle = lineAngle * 180 / Math.PI, CenterX = 0.5, CenterY = 0.5 };
            TranslateTransform translate = new TranslateTransform( lineEnd.X, lineEnd.Y );

            StreamGeometry streamGeometry = new StreamGeometry();
            using( StreamGeometryContext geometryContext = streamGeometry.Open() )
            {
                geometryContext.BeginFigure( lineStart, true, true );
                geometryContext.LineTo( lineEnd, true, true );

                //left arrow
                geometryContext.BeginFigure( lineStart, true, true );
                geometryContext.PolyLineTo( new List<Point>()
                {
                     rotation.Transform( new Point( 0, -15 ) ),
                     rotation.Transform( new Point( -15, 0 ) ),
                     rotation.Transform( new Point( 0, 15 ) )
                }, true, true );

                //right arrow
                geometryContext.BeginFigure( lineEnd, true, true );
                geometryContext.PolyLineTo( new List<Point>()
                {
                    translate.Transform( rotation.Transform( new Point( 0, -15 ) ) ),
                    translate.Transform( rotation.Transform( new Point( 15,0 ) ) ),
                    translate.Transform( rotation.Transform( new Point( 0, 15 ) ))
                }, true, true );
            }

            streamGeometry.Freeze();
            return streamGeometry;              
        }
    }
}

以下是它的表现:

enter image description here

如何在旋转时使箭头保持15x15的初始尺寸,特别是在接近180度或90度的角度时?

2 个答案:

答案 0 :(得分:2)

让我们考虑几何背景。你有一个中心,你有一个箭头。当角度改变时,箭头的长度不应改变。我们刚才描述的形状是什么?是的,你是对的,它是。现在,圆圈的属性是什么?其中心是您用作稳定点的(X1,Y1)点,其半径是箭头的初始长度。基本上,您打算根据中心,半径和角度找到终点。

假设角度为alpha。在这种情况下,您要搜索的(X2,Y2)坐标为:

  

X2 = X1 +半径* cos(alpha)

     

Y2 = Y1 +半径* sin(alpha)

答案 1 :(得分:0)

您应该像X1那样定义Y1X2Y2Line属性。

然后绘图可以像下面所示完成,可能用另一个依赖属性的值替换箭头尺寸的常量。它首先绘制一条带箭头的水平线,其中矢量的长度连接起点和终点,然后适当地旋转它。

protected override Geometry DefiningGeometry
{
    get
    {
        var vector = new Point(X2, Y2) - new Point(X1, Y1);
        var angle = Vector.AngleBetween(new Vector(1, 0), vector);
        var geometry = new StreamGeometry();

        using (var sgc = geometry.Open())
        {
            // left arrow
            sgc.BeginFigure(new Point(X1, Y1), true, true);
            sgc.LineTo(new Point(X1 + 15, Y1 - 10), true, true);
            sgc.LineTo(new Point(X1 + 15, Y1 + 10), true, true);

            // right arrow
            sgc.BeginFigure(new Point(X1 + vector.Length, Y1), true, true);
            sgc.LineTo(new Point(X1 + vector.Length - 15, Y1 - 10), true, true);
            sgc.LineTo(new Point(X1 + vector.Length - 15, Y1 + 10), true, true);

            // line
            sgc.BeginFigure(new Point(X1 + 15, Y1), false, false);
            sgc.LineTo(new Point(X1 + vector.Length - 15, Y1), true, true);
        }

        geometry.Transform = new RotateTransform(angle, X1, Y1);
        geometry.Freeze();

        return geometry;
    }
}