[原譯]WPF繪制圓角多邊形


介紹

最近,我發現我需要個圓角多邊形。而且是需要在運行時從用戶界面來繪制。WPF有多邊形。但是不支持圓角。我搜索了一下。也沒找到可行的現成例子。於是就自己做吧。本文描述了圓角多邊形的實現,也包括如何用在你的項目里。在Demo里面的RoundedCornersPolygon 類是完整的實現。

下載的Demo包括兩部分

1. 通過XAML繪制圓角多邊形

2. 運行時創建圓角多邊形

背景
多邊形可以被認為是沿着一個給定半徑的圓的邊緣和一些指定點/邊。所構成的點的集合。


在WPF中。你可以給Polygon對象的Points屬性添加一系列的點來制作多邊形。

XAML方式

<Canvas>
    <Polygon Points="10,50 180,50 180,150 10,150" 
       StrokeThickness="1" Stroke="Black" />
</Canvas>

 

C#方式

var cnv = new Canvas(); 
var polygon = new Polygon {StrokeThickness = 1, Fill = Brushes.Black};
polygon.Points.Add(new Point(10, 50)); 
polygon.Points.Add(new Point(180, 50));
polygon.Points.Add(new Point(180, 150));
polygon.Points.Add(new Point(10, 150));
cnv.Children.Add(polygon);
this.Content = cnv;

 

上面兩個例子會輸出下面的矩形

使用代碼
我寫的RoundedCornersPolygon 類和普通的多邊形類很相似。但是有更多的屬性來控制圓角。首先。看一個例子。展示一下圓角矩形類的使用

XAML方式

<Canvas>
    <CustomRoundedCornersPolygon:RoundedCornersPolygon Points="10,50 180,50 180,150 10,150" 
               StrokeThickness="1" Stroke="Black" ArcRoundness="25" 
               UseAnglePercentage="False" IsClosed="True"/>
<Canvas>

 

C#方式

var cnv = new Canvas();  
var roundedPolygon = new RoundedCornersPolygon
{
    Stroke = Brushes.Black, StrokeThickness = 1, 
    ArcRoundness = 25, UseAnglePercentage = false, IsClosed = true
};
roundedPolygon.Points.Add(new Point(10, 50));
roundedPolygon.Points.Add(new Point(180, 50));
roundedPolygon.Points.Add(new Point(180, 150));
roundedPolygon.Points.Add(new Point(10, 150));
cnv.Children.Add(roundedPolygon);
this.Content = cnv;

 

輸出如下:

多邊形有四個主要屬性
ArcRoundness 屬性指定了從距離LineSegment終點多遠的距離開始彎曲,通常和UseRoundnessPercentage 一起使用。UseRoundnessPercentage屬性指定了ArcRoundness 值是百分比還是一個固定的值。

舉個例子。ArcRoundness 被設置成10,而且UseRoundnessPercentage 被設置成false,那么彎曲將會在距離線段終點10的地方開始。而如果UseRoundnessPercentage 被設置成ture。則會是從線段終點10%的地方開始彎曲。

/// <summary> 
/// Gets or sets a value that specifies the arc roundness.
/// </summary>
public double ArcRoundness { get; set; }

/// <summary>  
/// Gets or sets a value that specifies if the ArcRoundness property
/// value will be used as a percentage of the connecting segment or not.
/// </summary>
public bool UseRoundnessPercentage { get; set; }

 

IsClosed 指定多邊形的最后一個點是否和第一個點閉合。為了成為一個多邊形。一般應該被設置為true

/// <summary> 
/// Gets or sets a value that specifies if the polygon will be closed or not.
/// </summary> 
public bool IsClosed { get; set; }
 

 

Points屬性則代表了多邊形點的集合。

/// <summary> 
/// Gets or sets a collection that contains the points of the polygon.
/// </summary>
public PointCollection Points{ get; set; } 

如何實現
控件實現了Shape 類,被用來畫多邊形的形狀是一個Path對象。我們會往Path對象里添加LineSegment 和QuadraticBezierSegment 對象。QuadraticBezierSegment 對象表示一個貝塞爾曲線。由三個點定義。更多的信息請查看

對於一個普通的多邊形,只有LineSegment是必須的,但是為了設計圓角多邊形。就需要貝塞爾曲線了。每一次一個點被添加/一個屬性被修改。形狀會重繪。做圓角的關鍵方式就是ConnectLinePoints 方法。

/// <summary>
/// 使用公共點連接兩條線段,
/// 通過3個點的指定來繪制彎曲部分
/// </summary>
/// <param name="pathFigure"></param>
/// <param name="p1">第一條線段的第一個點</param>
/// <param name="p2">第二個點,也是公共點</param>
/// <param name="p3">第二條線段的第二個點</param>
/// <param name="roundness">角的弧度</param>
/// <param name="usePercentage">標志值(百分比還是真值) </param>
private static void ConnectLinePoints(PathFigure pathFigure, Point p1, 
                                      Point p2, Point p3,
                                      double roundness, bool usePercentage)
{
      //第一條線段上彎曲部分開始的位置點.
      Point backPoint;
      //第二條線段上彎曲部分結束的位置點
      Point nextPoint;
      if (usePercentage)
      {
          backPoint = GetPointAtDistancePercent(p1, p2, roundness, false);
          nextPoint = GetPointAtDistancePercent(p2, p3, roundness, true);
      }
      else
      {
          backPoint = GetPointAtDistance(p1, p2, roundness, false);
          nextPoint = GetPointAtDistance(p2, p3, roundness, true);
      }            

      int lastSegmentIndex = pathFigure.Segments.Count - 1;
      //設置第一條線段的終點.
      ((LineSegment)(pathFigure.Segments[lastSegmentIndex])).Point = backPoint;

      //創建並添加彎曲部分
      var curve = new QuadraticBezierSegment { Point1 = p2, Point2 = nextPoint };
      pathFigure.Segments.Add(curve);

      /創建並添加新線段。
      var line = new LineSegment { Point = p3 };
      pathFigure.Segments.Add(line);
}

 

還有兩個方法計算彎曲部分開始的點GetPointAtDistance 和GetPointAtDistancePercent,第一個是以值計算,第二個是以百分比計算。

/// <summary>
///得到由兩個點定義的線段上,給定距離的點
/// </summary>
/// <param name="p1">第一條線段的第一個點</param>
/// <param name="p2">第一條線段的第二個點</param>
/// <param name="distance">點的距離</param>
/// <param name="firstPoint">標志值(百分比還是真值)</param>
/// <returns>計算結果點</returns>
private static Point GetPointAtDistance(Point p1, Point p2, 
                     double distance, bool firstPoint)
{
     double totalDistance = Math.Sqrt(Math.Pow((p2.X - p1.X), 2) + 
                            Math.Pow((p2.Y - p1.Y), 2));
     double rap = firstPoint ? distance / totalDistance : 
                   (totalDistance - distance) / totalDistance;
     return new Point(p1.X + (rap * (p2.X - p1.X)), p1.Y + (rap * (p2.Y - p1.Y)));
}

private static Point GetPointAtDistancePercent(Point p1, Point p2, 
                     double distancePercent, bool firstPoint)
{
     double rap = firstPoint ? distancePercent / 100 : (100 - distancePercent) / 100;
     return new Point(p1.X + (rap * (p2.X - p1.X)), p1.Y + (rap * (p2.Y - p1.Y)));
}
 

 

結論
依然有很多細節應該完善的。但這僅僅是圓角多邊形的一個嘗試。比如。在其他情況。每個角應該有不同晚景的圓角,WPF使得一切皆有可能。本文的目的是創建一個大家可以用的圓角多邊形,他們可以擴展來滿足他們的需求。

Demo下載

圓角多邊形

許可
本文包括源代碼和文件在CPOL下授權。

原文地址:WPF-rounded-corners-polygon

著作權聲明:本文由http://leaver.me 翻譯,歡迎轉載分享。請尊重作者勞動,轉載時保留該聲明和作者博客鏈接,謝謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM