3
votes

What I want to do overall is add an ellipse to a canvas to represent the position of a golf ball on the Circumference of a circle when it is struck at a certain angle by a golf putter from the center of that circle. To do this I am using two images one which is a circle divided up into sections to represent the angle the ball was struck at. The other image is just a putter head that is rotated to represent the angle which the club hits the ball at. This image sits on top of the circle image. The blue ellipse represents the position of the ball.See the image output got from my application in the link below:

Required application output

To do this I basically calculated the width and height of the grid using this code:

public FacePage()
{
    InitializeComponent();
    GridGraphs.SizeChanged += GridGraphs_SizeChanged;
}

void GridGraphs_SizeChanged(object sender, SizeChangedEventArgs e)
{
    GetMeasurements();
}

private void GetMeasurements()
{
    GridGraphs.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));

    double width = GridGraphs.DesiredSize.Width;
    double height = GridGraphs.DesiredSize.Height;

    RotatePutter(width, height);
}

and then passed the width and height into RotatePutter() where the the width and height was divided by two to get the centre point of the grid see below:

public void RotatePutter(double width, double height)
{

    double radius = width * 0.5;
    double centerX = width * 0.5;
    double centerY = height * 0.5;

    Random ran = new Random();
    double angle = ran.Next(-15, 15);

    if (angle >= 0)
    {
        if (angle <= 5)
        {
            lblShotStaus.Content = "Square";
        }
        else
        {
            lblShotStaus.Content = "Open";
        }
    }
    else
    {
        lblShotStaus.Content = "Closed";
    }

    double angleradians = (angle * (Math.PI / 180));

    Point putterCentre = new Point(0.5, 0.5);

    imgPutter.RenderTransformOrigin = putterCentre;

    RotateTransform rt = new RotateTransform(angle, 0.5, 0.5);
    imgPutter.RenderTransform = rt;

    BallLocation(radius, angleradians, centerX, centerY);
}

The centre point,radius,angle and the putter Image is rotated here and the radius, angleradians,centerX and centerY are passed to BallLocation to calculate the position of the Ball like so:

public void BallLocation(double rad, double anglerad, double centerX, double centerY)
{
    Ellipse ellipse = new Ellipse();

    double xBallPoint = (centerX - (rad * Math.Cos(anglerad)));
    double yBallPoint = (centerY - (rad * Math.Sin(anglerad)));

    ellipse.Height = 10;
    ellipse.Width = 10;
    ellipse.Fill = new SolidColorBrush(Colors.Aqua);

    Canvas.SetLeft(ellipse, xBallPoint);
    Canvas.SetTop(ellipse, yBallPoint);
    canvasFaceAngle.Children.Add(ellipse);
}

This works ok in full screen put once I change the size of the window the position of the ball for the angle it was hit at is all wrong.

Would anyone have any idea how to dynamically get the grid width and height as the window size changes so to calculate the correct position for the ellipse (ball). Or any other alternative ways of completing this is also welcomed. Thanks in advance.

Here is my xaml:

<UserControl x:Class="HoleMorePuttsApplication.Pages.FacePage"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="40*"/>
        <ColumnDefinition Width="60*"/>
    </Grid.ColumnDefinitions>
    <Viewbox Grid.ColumnSpan="1">
        <Label Content="Face Angle Page" FontWeight="Bold" />
    </Viewbox>
    <Grid Name="GridGraphs" Column="1">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Name="columnLeft" Width="50*"/>
            <ColumnDefinition Name="columnRight" Width="50*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Name="rowTop" Height="70*"/>
            <RowDefinition Name="rowBottom" Height="30*"/>
        </Grid.RowDefinitions>

        <Image x:Name="imgAngles"  Source="C:\Users\BernardWork\Documents\Work\Net\PuttingApp\Images\360Angles.jpg" Grid.ColumnSpan="2" HorizontalAlignment="Left" VerticalAlignment="Top"/>
        <Image x:Name="imgPutter"   Source="C:\Users\BernardWork\Documents\Work\Net\PuttingApp\Images\Putter.jpg" Opacity="0.5" Margin="130,105,70,105" Grid.ColumnSpan="2" HorizontalAlignment="Left" VerticalAlignment="Bottom"/>
        <Label x:Name="lblShotStaus" Content="Label" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
        <Canvas Name="canvasFaceAngle" Grid.ColumnSpan="2" Grid.Row="0" RenderTransformOrigin="0.543,0.511"></Canvas>


    </Grid>

</Grid>

2

2 Answers

1
votes

If I understand correct, I believe the problem may be with:

double width = GridGraphs.DesiredSize.Width;
double height = GridGraphs.DesiredSize.Height;

You are calling Measure with no bounds provided which means that it will tell you the size the Grid would be were there no limitations (hence, the DesiredSize). The DesiredSize and the ActualSize may be two very different values.

In the case above, the args of the SizeChanged method will provide you with what you need.

void GridGraphs_SizeChanged(object sender, SizeChangedEventArgs e)
{
    RotatePutter(e.NewSize.Width, e.NewSize.Height);
}
0
votes

So if the goal is just to get the grid width/height, the ActualWidth and ActualHeight properties should give you that information. One thing to be careful about though: while the Grid control changes size along with the window, the Canvas control does not. In other words, if you read the actualwidth/height of a grid, it should correspond to the side of the window, but if you read the actualwith/height of a canvas, it will probably give you incorrect information.