【问题标题】:WPF Custom Shape Alternating Arc SegmentsWPF 自定义形状交替弧段
【发布时间】:2019-06-05 23:06:01
【问题描述】:

我正在尝试使用一系列弧段在 WPF 中创建自定义形状。形状本质上是一个带有断线的圆形,像这样

虽然我知道我可以使用 Ellipse 并设置破折号数组属性来实现类似的效果,但我需要处理不断变化的厚度和半径,即我必须保持可见段的数量不变,而使用破折号会变得很困难数组属性,因为它相对于笔画粗细。

因此,我尝试创建类似于 SO 问题 here 的自定义形状。该答案中描述的形状仅与绘制单个弧线有关,而我需要绘制一系列中间有间隙的弧线。这就是我正在尝试的

 for ( int i = 1; i <= Segments; i++ )
 {
    var endpoint = PolarToCartesian(sweepAngle * i, Radius);    
    var drawArcSegment = i % 2 == 0;

    if (drawArcSegment)
    {
        var arcSegment = new ArcSegment
        {
           Point = endpoint,
           Size = new Size(Radius, Radius),
           IsLargeArc = false,
           SweepDirection = SweepDirection.Clockwise
        };
    }
    else
    {
        // WHAT TO DO HERE?
        // Need to either draw an arc segment that can't be seen but I can't apply
        // style properties to an arc segment OR need to move the current point of the
        // parent path figure to a new point that is the start of the following segment
    }
 }

这可能吗?我是否以正确的方式处理这个问题?

【问题讨论】:

    标签: wpf custom-controls


    【解决方案1】:

    真的计算一个合适的划线模式并不难。

    给定一个带有 EllipseGeometry 的路径(其中半径的定义比 Ellipse 元素更精确)

    <Path x:Name="path" StrokeThickness="20" Stroke="Black">
        <Path.Data>
            <EllipseGeometry RadiusX="100" RadiusY="100"/>
        </Path.Data>
    </Path>
    

    您可以像这样计算StrokeDashArrayStrokeDashOffset 属性:

    var ellipse = (EllipseGeometry)path.Data;
    var strokeLength = 2 * Math.PI * ellipse.RadiusX / path.StrokeThickness;
    
    var numSegments = 8;
    var relativeSegmentLength = 0.75;
    
    var segmentLength = strokeLength / numSegments * relativeSegmentLength;
    var gapLength = strokeLength / numSegments * (1 - relativeSegmentLength);
    
    path.StrokeDashArray = new DoubleCollection { segmentLength, gapLength };
    path.StrokeDashOffset = -gapLength / 2;
    

    【讨论】:

      【解决方案2】:

      为每个 ArcSegment 启动一个新的 PathFigure,因此路径不必是连续的。

      或者使用 Clemens 的回答,这样更好。

      public PathGeometry CreateGeometry(int segmentCount, double radius)
      {
          double sweepAngle = 360.0 / (double)segmentCount;
          double segmentAngle = sweepAngle / 2;
      
          double startAngleOffset = segmentAngle * 0.3;
          double endAngleOffset = segmentAngle * 1.7;
      
          var pg = new PathGeometry();
      
          for (int i = 0; i < segmentCount; ++i)
          {
              double currentSegmentAngle = i * sweepAngle;
      
              pg.Figures.Add(new PathFigure
              {
                  StartPoint = PolarToCartesian(currentSegmentAngle + startAngleOffset, radius),
                  Segments = {
                      new ArcSegment{
                          Size = new Size(radius, radius),
                          SweepDirection = SweepDirection.Clockwise,
                          IsLargeArc = false,
                          Point = PolarToCartesian(currentSegmentAngle + endAngleOffset, radius)
                      }
                  }
              });
          }
      
          return pg;
      }
      

      笔画粗细与您的不太一样,但您可以弄清楚。这里的线帽是半径。在您的情况下,它们不是:您的情况就好像有人在半径范围内擦除了一条宽线。如果你想要那样,你不能让中风为你做这项工作。您必须绘制闭合和填充的 PathFigure,每个都有两条弧线和两条末端线。

      【讨论】:

        猜你喜欢
        • 2022-01-04
        • 1970-01-01
        • 1970-01-01
        • 2021-01-23
        • 2014-06-21
        • 1970-01-01
        • 1970-01-01
        • 2017-03-05
        • 2015-06-21
        相关资源
        最近更新 更多