2

Есть у меня пятиконечная звезда.

<ed:RegularPolygon x:Name="regularPolygon" Fill="{StaticResource RatingButtonNormalFill}" InnerRadius="0.55" PointCount="5" Stroke="Black" 
                       StrokeThickness="0.5" RenderTransformOrigin="0.5,0.5" Width="{TemplateBinding ActualWidth}" Height="{TemplateBinding ActualHeight}">

Есть с ней проблема. На форме она маленькая (20х20) и она при клике вращается. Так вот при вращении она как бы сдвигается немного.

Я полагаю, что это из-за того, что когда звезда вращается, размеры описывающего ее ректа меняются (ведь контейнер не вращается вместе с ней) и она на ходу подгоняет свои размеры. Пока не знаю, что с этим делать. Может, причина и не в этом.

UPD

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

Картинка 1 (без поворота)

А вот я повернул пятиугольник на 72 градуса (то есть чтобы наверху оказалась следующая его вершина).

Картинка 2 (поворот на 72 градуса)

Пока не знаю что делать с этим.

UPD2

Короче геометрическое решение нашел... надо только как то в xaml это перенести. Суть в том, что квадрат, в котором у меня находится звезда, должен описывать круг, в который вписана звезда. Как это перенести в xaml я не знаю :(

введите сюда описание изображения

UPD3

Нужно перенести центр вращения в центр круга, описывающего звезду. Самого круга конечно же нет. Надо изменить свойство RenderTransformOrigin="0.5,0.5", но я пока не знаю на что

iRumba
  • 5,946
  • Не, у вас же RenderTransform, размеры не меняются. Судя по всему, ed:RegularPolygon не точно центрует вашу звезду. Покажите его код. – VladD Feb 25 '17 at 18:00
  • @VladD, звезда вращается на 72 градуса (то есть наверху должна оказываться следующая ее вершина). Проблема в том, что правильный пятиугольник не вписывается в квадрат. Я только что в ворде повращал пятиугольник на квадрате. Короче с причиной я угадал, но пока не знаю что делать с этим – iRumba Feb 25 '17 at 18:08
  • @VladD, посмотрите обновление – iRumba Feb 25 '17 at 18:18
  • Это правда, правильный пятиугольник не вписывается в квадрат. Но он обязан быть расположен так, чтобы его центр в точности совпадал с центром квадрата. При этом верхняя вершина не будет упираться в верхнюю сторону квадрата, но это нормально. – VladD Feb 25 '17 at 18:29
  • Иначе при вращении вокруг центра квадрата будут, понятно, проблемы. То есть ошибка должна быть в ed:RegularPolygon. Давайте его код :) – VladD Feb 25 '17 at 18:30
  • @VladD, у меня нет его кода. ed: - xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing". Пятиугольник и расположен так, что его центр находится в центре квадрата. Вот только пятиугольник описывает не квадрат а прямоугольник. А если прямоугольник повернуть в квадрате на 72 градуса, получается лажа. попробуйте сами. Короче решение (чисто геометрически) такое. Нужно вписать пятиугольник в окружность, а окружность уже в квадрат. Тогда все получается норм. но как это сделать в XAML я хз – iRumba Feb 25 '17 at 18:35
  • @VladD смотрите upd2 – iRumba Feb 25 '17 at 18:39
  • Подождите, а откуда он взялся? Это из стандартных контролов? – VladD Feb 25 '17 at 18:59
  • То решение, которое вы описываете, и есть совмещение центров. – VladD Feb 25 '17 at 19:00
  • Ага, нашёл, сейчас напишу решение. – VladD Feb 25 '17 at 19:03
  • @VladD центров чего? На последнем рисунке центр ректа звезды не совпадает с центром квадрата. И не должен совпадать, чтобы все получилось. Зато центр квадрата совпадает с центром круга.... короче тут как я понял нужно через конвертер высчитывать ширину звезды по ширине заданного квадрата, так, чтобы диаметр описывающей звезду окружности был равен стороне квадрата. – iRumba Feb 25 '17 at 19:19

1 Answers1

6

Класс RegularPolygon, к сожалению, никуда не годится: он не центрирует фигуру вокруг геометрического центра, а наоборот растягивает свою высоту и ширину, так что получается вовсе не правильный многоугольник!

Чтобы было правильно, проще всего посчитать самому. У меня работает такой код:

<Grid Background="#D08435">
    <Path Data="M -1,-1
                M 0,-1
                L 0.95105651629515357211643933337938,-0.30901699437494742410229341718282
                L 0.58778525229247312916870595463907,0.80901699437494742410229341718282
                L -0.58778525229247312916870595463907,0.80901699437494742410229341718282
                L -0.95105651629515357211643933337938,-0.30901699437494742410229341718282
                L 0,-1
                M 1,1"
          Stretch="Uniform" 
          Fill="#7093D0"
          RenderTransformOrigin="0.5,0.5"/>
</Grid>

(Коэффициенты при L — синусы и косинусы углов, кратных 72°.)

Я добавил вращение к Path, получилось вот что:

анимашка


Если нужен переменный внутренний радиус, проще, наверное, сделать через конвертер.

class StarGeometryConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter,
                          CultureInfo culture)
    {
        return CreateStarGeometry((int)parameter, (double)value);
    }

    Geometry CreateStarGeometry(int numberOfVertices, double innerRadius)
    {
        var edge1 = new PathFigure() { StartPoint = new Point(-1, -1) };
        var edge2 = new PathFigure() { StartPoint = new Point(1, 1) };
        var segments = new List<PathSegment>();
        var step = Math.PI * 2 / numberOfVertices;
        foreach (var angle in Enumerable.Range(0, numberOfVertices).Select(n => n * step))
        {
            segments.Add(new LineSegment(
                             new Point(Math.Sin(angle),
                                       -Math.Cos(angle)),
                             isStroked: true));
            segments.Add(new LineSegment(
                             new Point(innerRadius * Math.Sin(angle + step / 2),
                                       -innerRadius * Math.Cos(angle + step / 2)),
                             isStroked: true));
        }
        var figure = new PathFigure(new Point(0, -1), segments, closed: true);
        return new PathGeometry(new[] { edge1, figure, edge2 });
    }

    public object ConvertBack(object value, Type targetType, object parameter,
                              CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

С ним получаем такой XAML:

<Window.Resources>
    <sys:Int32 x:Key="NumberOfVertices">5</sys:Int32>
    <sys:Double x:Key="InnerRadius">0.6</sys:Double>
    <local:StarGeometryConverter x:Key="StarConverter"/>
</Window.Resources>
<Grid Background="#D08435">
    <Path Data="{Binding Source={StaticResource InnerRadius},
                         Converter={StaticResource StarConverter},
                         ConverterParameter={StaticResource NumberOfVertices}}"
          Stretch="Uniform" 
          Fill="#7093D0"
          RenderTransformOrigin="0.5,0.5"/>
</Grid>

Результат:

Ещё анимашка

VladD
  • 206,799
  • Спасибо, только в итоге у меня возникнет еще куча проблем с использованием Path. Во-первых, RegularPolygon позволяет задать внутренний радиус, чтобы из многоугольника сделать звезду, а это позволяет мне гибко изменять внешний вид звезды одним параметром (правильная мне не нравится). – iRumba Feb 26 '17 at 15:40
  • Во-вторых, центрируется все как раз таки по геометрическому центру. Просто правильный пятиугольник находится внутри прямоугольника, а не квадрата, но для правильного вращения нужен именно квадрат. То есть центр вращения должен быть там, где находится центр описывающего звезду круга. Я пока буду смотреть именно в этом направлении. – iRumba Feb 26 '17 at 15:42
  • @iRumba: Ну уж вам не угодишь. Обновил ответ. – VladD Feb 26 '17 at 17:54
  • Спасибо! :) Просто я хотел максимально абстрагироваться от геометрии (как науки). Не помню я ее :( – iRumba Feb 27 '17 at 02:36
  • @iRumba: Пожалуйста! Понимаю, хочется готовых и правильных контролов, но к сожалению RegularPolygon требует всё равно применения тригонометрии. В общем, от неё не спастись :) – VladD Feb 27 '17 at 09:49