Nano Hash - криптовалюты, майнинг, программирование

С# WPF, как нарисовать дугу в сетке с помощью кода позади

У меня есть сетка, которая адаптируется к столбцам и строкам. В этой сетке я должен нарисовать дугу, которая простирается до всей родительской сетки.

я пробовал это

Canvas cnv = new Canvas();
Path pth = new Path() { HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch };
PathGeometry pg = new PathGeometry();
PathFigureCollection pfc = new PathFigureCollection();
PathFigure pf = new PathFigure();

ArcSegment a = new ArcSegment(new Point(0, 0), new Size(300, 300), 45, true, SweepDirection.Clockwise, true);

cnv.Children.Add(pth);
pth.Data = pg;
pfc.Add(pf);
pg.Figures = pfc;
pf.Segments.Add(a);
grd.Children.Add(cnv);

но ничего не появляется.

Кроме того, мне интересно, есть ли более простое решение для достижения цели.

И потом, я не хочу задавать размер дуги, я хочу, чтобы она растянулась до родительского размера, возможно, с запасом.

Большое тебе спасибо

29.05.2017

  • Почему вы сначала добавляете pth на холст, а затем изменяете pth? Вы должны заполнить элемент данными и после этого добавить его к родителю (холсту) 29.05.2017
  • Не могли бы вы привести пример? Кстати, как я могу установить цвет дуги?!?!? 29.05.2017
  • Пожалуйста, обратитесь по этой ссылке круг с использованием сегмента дуги между двумя произвольными точками"> stackoverflow.com/questions/5336131/ 29.05.2017
  • Есть ли причина, по которой вы хотите сделать это в коде программной части? 29.05.2017
  • @KamilSolecki Мне нужно создавать плагины с помощью технологии appdomain. Так что нет интерфейса, но я должен построить всю графику во время выполнения. 29.05.2017
  • @RashipSaiyed спасибо, это может быть полезно, но у него фиксированный размер, а мне нужно расширить его, чтобы заполнить его родителя. 29.05.2017
  • ArcSegment всегда имеет фиксированный размер, основанный на точках/координатах. Вам придется их вычислить. 29.05.2017
  • @mm8 спасибо за разъяснение, но как мне это сделать? и ширина, и высота равны нулю и одинаковы для ActualWidth и ActualHeight. 29.05.2017
  • Я не знаю, о каком размере вы говорите. Пожалуйста, прочитайте мой ответ. 29.05.2017
  • Я сделал. Я должен поместить дугу в сетку. Эта сетка должна адаптироваться к системе определения столбца/строки, чтобы она была динамичной. Если я не ошибаюсь, мне нужно рассчитать высоту и ширину сетки. Но когда я это сделаю, поскольку он динамический, он всегда даст мне размер 0,0. 29.05.2017
  • Теперь ты видишь путь? 29.05.2017
  • Да, спасибо, я отмечу ваше решение. Но без возможности установить ширину и высоту его нельзя использовать. 29.05.2017
  • Какая ширина и высота? 29.05.2017

Ответы:


1

Если вы не можете получить доступ к ActualWidth и ActualHeight, это значит, что сетка еще не загружена. Я предлагаю поместить код в событие gridLoaded. Кроме того, я настоятельно рекомендую это решение значительно упрощает рисование дуг.

Итак, в конструкторе:

grd.Loaded += Grd_Loaded;

а затем после того, как событие было запущено

private void Grd_Loaded(object sender, RoutedEventArgs e)
{
    Canvas cnv = new Canvas();
    Path pth = new Path();
    pth.Fill = Brushes.Transparent;
    pth.Stroke = Brushes.GreenYellow;
    pth.StrokeThickness = 20;

    PathGeometry pg = new PathGeometry();
    PathFigureCollection pfc = new PathFigureCollection();

    PathFigure pf = new PathFigure();
    double dim = grd.ActualHeight;
    arcs = new Arc();
    arcs.Center = new Point(dim / 2, dim / 2);
    arcs.StartAngle = 0;
    arcs.EndAngle = 0;
    arcs.Radius = dim / 2;
    arcs.Stroke = Brushes.YellowGreen;
    arcs.StrokeThickness = 20;
    arcs.SmallAngle = false;
    cnv.Children.Add(arcs);

    grd.Children.Insert(0, cnv);

}

29.05.2017

2

Конечная точка дуги не должна быть равна 0,0. Установите его в допустимую точку, а также установите свойства Stroke и Fill для Path:

Canvas cnv = new Canvas();
Path pth = new Path();
pth.Fill = Brushes.BlueViolet;
pth.Stroke = Brushes.OrangeRed;

PathGeometry pg = new PathGeometry();
PathFigureCollection pfc = new PathFigureCollection();

PathFigure pf = new PathFigure();

ArcSegment a = new ArcSegment(new Point(200, 100), new Size(300, 300), 45, true, SweepDirection.Clockwise, true);

cnv.Children.Add(pth);
pth.Data = pg;
pfc.Add(pf);
pg.Figures = pfc;
pf.Segments.Add(a);
grd.Children.Insert(0, cnv);
29.05.2017

3

Я надеюсь, что это поможет любому озадаченному человеку. Я сам искал это безуспешно. Если это средство от проблемы, я так счастлив ;) ... это простая математическая концепция, которая много раз пинала в задницу. Это код, который мы используем:

 /// <summary>
  /// Defines an arc
  /// </summary>
  /// <seealso cref="System.Windows.Shapes.Shape" />
  public class Arc : Shape
  {
    /// <summary>
    /// Initializes the <see cref="Arc"/> class.
    /// </summary>
    // Angle that arc starts at
    public double StartAngle
    {
      get => (double)GetValue(StartAngleProperty);
      set => SetValue(StartAngleProperty, value);
    }

// DependencyProperty - StartAngle
    private static PropertyMetadata startAngleMetadata =
            new FrameworkPropertyMetadata(
                0.0,     // Default value
                FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure,
                null,    // Property changed callback
                new CoerceValueCallback(CoerceAngle))
            {
            };   // Coerce value callback

    public static readonly DependencyProperty StartAngleProperty =
        DependencyProperty.Register("StartAngle", typeof(double), typeof(Arc), startAngleMetadata);

    // Angle that arc ends at
    public double EndAngle
    {
      get => (double)GetValue(EndAngleProperty);
      set => SetValue(EndAngleProperty, value);
    }

    // DependencyProperty - EndAngle
    private static PropertyMetadata endAngleMetadata =
            new FrameworkPropertyMetadata(
                90.0,     // Default value
                FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure,
                null,    // Property changed callback
                new CoerceValueCallback(CoerceAngle));   // Coerce value callback

    public static readonly DependencyProperty EndAngleProperty =
        DependencyProperty.Register("EndAngle", typeof(double), typeof(Arc), endAngleMetadata);

    /// <summary>
    /// Coerces the angle.
    /// </summary>
    /// <param name="depObj">The dep object.</param>
    /// <param name="baseVal">The base value.</param>
    /// <returns></returns>
    private static object CoerceAngle(DependencyObject depObj, object baseVal)
    {
      double angle = (double)baseVal;
      angle = Math.Min(angle, 360.0);
      angle = Math.Max(angle, 0.0);
      return angle;
    }


    /// <summary>
    /// Gets or sets the sweep direction.
    /// </summary>
    /// <value>
    /// The sweep direction.
    /// </value>
    public SweepDirection SweepDirection
    {
      get => (SweepDirection)GetValue(SweepDirectionProperty);
      set => SetValue(SweepDirectionProperty, value);
    }

    // Using a DependencyProperty as the backing store for SweepDirection.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SweepDirectionProperty =
        DependencyProperty.Register("SweepDirection", typeof(SweepDirection), typeof(Arc), new FrameworkPropertyMetadata(
                SweepDirection.Counterclockwise,     // Default value
                FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure,
                null));



    /// <summary>
    /// Gets a value that represents the <see cref="T:System.Windows.Media.Geometry" /> of the <see cref="T:System.Windows.Shapes.Shape" />.
    /// </summary>
    protected override Geometry DefiningGeometry
    {
      get
      {
        var width = Visibility == Visibility.Visible ? ActualWidth : 0.0;
        var height = Visibility == Visibility.Visible ? ActualHeight : 0.0;

        double maxWidth = Math.Max(0.0, width - StrokeThickness);
        double maxHeight = Math.Max(0.0, height - StrokeThickness);

        if (maxWidth == 0
          || maxHeight == 0)
        {
          return new StreamGeometry();
        }

        var arcSize = new Size(maxWidth / 2.0, maxHeight / 2);
        var calculator = new ElipticCurveCalculator(new Size(width, height), new Size(maxWidth / 2, maxHeight / 2));

        var angle = EndAngle - StartAngle;
        var firstAngle = Math.Min(angle, 180);
        var secondAngle = Math.Max(angle - 180, 0);

        // start = 20; end = 200; angle = 180
        var firstStart = SweepDirection == SweepDirection.Clockwise ? -StartAngle : StartAngle;
        var firstEndAngle = SweepDirection == SweepDirection.Clockwise ? firstStart - firstAngle : firstStart + firstAngle;

        var secondEndAngle = 0.0;
        if (secondAngle > 0)
        {
          secondEndAngle = SweepDirection == SweepDirection.Clockwise ? firstStart - firstAngle - secondAngle : firstStart + firstAngle + secondAngle;
        }

        var p1Start = calculator.GetPoint(firstStart);
        var p1End = calculator.GetPoint(firstEndAngle);

        StreamGeometry geom = new StreamGeometry();
        using (StreamGeometryContext ctx = geom.Open())
        {
          ctx.BeginFigure(p1Start,
              false,
              false);

          ctx.ArcTo(p1End,
              arcSize,
              0.0,     // rotationAngle
             false,   // greater than 180 deg?
              SweepDirection,
              true,    // isStroked
              true);

          if (secondEndAngle != 0)
          {
            var p2End = calculator.GetPoint(secondEndAngle);

            ctx.ArcTo(
              p2End,
              arcSize,
              0.0,     // rotationAngle
             false,   // greater than 180 deg?
              SweepDirection, // == SweepDirection.Clockwise ? SweepDirection.Counterclockwise : SweepDirection.Clockwise,
              true,    // isStroked
              true);
          }
        }

        geom.Freeze();

        return geom;
      }
    }

    private double GetFistAngle(double startAngle, double angle)
    {
      var endAngle = SweepDirection == SweepDirection.Counterclockwise
        ? Math.Min(startAngle - angle, 180)
        : Math.Min(angle - startAngle, 180);

      return endAngle;
    }
  }

  /// <summary>
  /// Calculates points for an eliptic curve
  /// </summary>
  class ElipticCurveCalculator
  {
    /// <summary>
    /// The point calculator
    /// </summary>
    private readonly EllipsePointCalculator _ellipsePointCalculator;

    /// <summary>
    /// The half of a box size
    /// </summary>
    private readonly Size _boxSizeHalf;

    /// <summary>
    /// Initializes a new instance of the <see cref="ElipticCurveCalculator"/> class.
    /// </summary>
    /// <param name="boxSize">Size of the box.</param>
    /// <param name="arcSize">Size of the arc.</param>
    public ElipticCurveCalculator(Size boxSize, Size arcSize)
    {
      _ellipsePointCalculator = new EllipsePointCalculator(arcSize);
      _boxSizeHalf = new Size(boxSize.Width / 2, boxSize.Height / 2);
    }

    /// <summary>
    /// Gets the point.
    /// </summary>
    /// <param name="angle">The angle.</param>
    /// <returns></returns>
    public Point GetPoint(double angle)
    {
      var point = new Point(_boxSizeHalf.Width, _boxSizeHalf.Height);

      var offset = _ellipsePointCalculator.GetPoint(angle);

      point.Offset(offset.X, -offset.Y);

      return point;
    }
  }

  /// <summary>
  /// Calculates ellipse points based on simple math
  /// </summary>
  public class EllipsePointCalculator
  {
    /// <summary>
    /// Initializes a new instance of the <see cref="EllipsePointCalculator"/> class.
    /// </summary>
    /// <param name="size">The size of the ellipse.</param>
    public EllipsePointCalculator(Size size) => Size = size;

    /// <summary>
    /// Gets the size.
    /// </summary>
    /// <value>
    /// The size.
    /// </value>
    public Size Size { get; }

    /// <summary>
    /// Gets the point.
    /// </summary>
    /// <param name="angle">The angle.</param>
    /// <returns></returns>
    public Point GetPoint(double angle)
    {
      switch (angle)
      {
        case 0:
        case 360:
          return new Point(Size.Width, 0);

        case 90:
          return new Point(0, Size.Height);
        case 180:
          return new Point(-Size.Width, 0);
        case 270:
          return new Point(0, -Size.Height);

        default:
          break;
      }

      double x = Size.Width * Math.Cos(angle * Math.PI / 180.0);
      double y = Size.Height * Math.Sin(angle * Math.PI / 180.0);

      return new Point(x, y);
    }
  }`

If any can update this code to work better ;) please do so!  :P 
26.10.2020
Новые материалы

Кластеризация: более глубокий взгляд
Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

Как написать эффективное резюме
Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

Частный метод Python: улучшение инкапсуляции и безопасности
Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

Как я автоматизирую тестирование с помощью Jest
Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..