3

My Math teacher asked me to write a program to plot a graph. I really don't know what I must implement, so I decided to draw a sin function. As I have some experience in Windows Phone development, I decided to write it in WPF. So I wrote the following XAML:

<Window x:Class="DemoMath.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:DemoMath"
        mc:Ignorable="d"
        Title="MathDemo" DataContext="{Binding RelativeSource={RelativeSource Self}}" Height="301.645" Width="525">
            <StackPanel VerticalAlignment="Center" Grid.Row="1">

            <Canvas Background="CornflowerBlue" x:Name="drawingSurface" Height="128">
                <TextBlock Width="{Binding ActualWidth, ElementName=drawingSurface}" Canvas.Top="25" x:Name="placeholder"  FontSize="40" Foreground="#FFF"  Text="Graph" TextAlignment="Center" FontFamily="Segoe Print"/>
                <Polyline Points="{Binding Graph2DPoints, Converter={StaticResource PointConverter}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Stroke="White" StrokeThickness="2" Visibility="Collapsed" x:Name="graph2D"/>
                <Polyline Visibility="Collapsed" x:Name="scale"/>
            </Canvas>
            <Grid>
                <Button x:Name="button" Click="Button_Click_1" Width="100">
                    <Button.Content>
                        <TextBlock Text="Generate" FontSize="16" FontFamily="Times New Roman"/>
                    </Button.Content>
                </Button>
            </Grid>
        </StackPanel>
</Window>

And C# code:

    public class ToPointCollection : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if(value!=null)
                return new PointCollection(value as ObservableCollection<Point>);
            return null;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return null;
        }
    }
    public partial class MainWindow : Window , INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        private void RaisePropertyChanged(string propertyName)
        {
            var handlers = PropertyChanged;
            handlers(this, new PropertyChangedEventArgs(propertyName));
        }
        ObservableCollection<Point> _graph2DPoints = new ObservableCollection<Point>();
        public ObservableCollection<Point> Graph2DPoints
        {
            get
            {
                return _graph2DPoints;
            }
            set
            {
                _graph2DPoints = value;
                RaisePropertyChanged("Graph2DPoints");
            }
        }
        Timer timer = new Timer() { Interval=1, AutoReset=true };
        double HeightSurface;
        public MainWindow()
        {
            InitializeComponent();
            Graph2DPoints.CollectionChanged += (s, e) => { RaisePropertyChanged("Graph2DPoints"); };
            timer.Elapsed += Timer_Elapsed;
            HeightSurface = drawingSurface.Height / 2;
        }
private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            timer.Stop();
            button.Visibility = Visibility.Collapsed;
            placeholder.Visibility = Visibility.Collapsed;

            List<Point> GraphPoints = new List<Point>(), scalePoints = new List<Point>();
            for (double phi = 0.0; phi <= 4* Math.PI; phi = phi + 0.1)
            {
                phi = Math.Round(phi, 2);
                var cosValue = -Math.Cos(phi);
                scalePoints.Add(new Point(20 + phi * 15, drawingSurface.Height / 2));
                Graph2DPoints.Add(new Point(20 + phi * 15, drawingSurface.Height / 2 + cosValue * 15));
            }
            scale.Points = new PointCollection(scalePoints);
            scale.Stroke = new SolidColorBrush(Colors.WhiteSmoke);
            scale.StrokeThickness = 1;
            graph2D.Visibility = Visibility.Visible;
            scale.Visibility = Visibility.Visible;
            graph3D.Visibility = Visibility.Collapsed;

            timer.Start();
        }
        double phase = Math.PI/2+0.1;
        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            timer.Stop();
            for (int i = 0; i < Graph2DPoints.Count; i++)
            {
                Graph2DPoints[i] = new Point(Graph2DPoints[i].X - 0.5, Graph2DPoints[i].Y);
            }
            if (Graph2DPoints[0].X < 0)
            {
                Graph2DPoints.RemoveAt(0);
                Point p = Graph2DPoints.Last();
                System.Diagnostics.Debug.WriteLine(p.X);
                Graph2DPoints.Add(new Point(p.X + 4.5, HeightSurface - Math.Cos(phase) * 15));
            }
            phase += 0.1;
            if (phase >= 5*Math.PI/2)
                phase = Math.PI / 2;

            phase = Math.Round(phase, 2);
            timer.Start();
        }
    }
}

After some time, it shows something strange, and System.Diagnostics.Debug.WriteLine(p.X); returns only one value:

enter image description here

1 Answer 1

1

Okay! Good job First of all!

What you refer as After some time is actually when the program starts to run the body for if (Graph2DPoints[0].X < 0) statement.

The reason for the weird behavior is that there is an inconsistency between these two lines:

for (int i = 0; i < Graph2DPoints.Count; i++)
        {
            Graph2DPoints[i] = new Point(Graph2DPoints[i].X - 0.5, Graph2DPoints[i].Y);
        }

and

Graph2DPoints.Add(new Point(p.X + 4.5, HeightSurface - Math.Cos(phase) * 15));

The problem is that in the top part of the code you are advancing your graph by -0.5 pixels, where as in the second part you are advancing it by 4.5 !

I advise you to set -0.5 to -4.5 and try it again! as you see that, the problem is gone. however you might complaint about the wider length of the wavelength. well there are two options for you:

1- Instead of 4.5 , use a lower value like 2.5 ! 2- Try multiplying Y values into something so it looks better.

Also there is a little glitch at the start, which you can solve it with changing the start phase.

;) have fun.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks a lot! :) That was helpful, I figured, that double phase = Math.PI*2-1.2; and shifting by 1.5 (I have remembered, that I was multiplying on 15, and found this value) have resloved the problem :) May I ask you one more question? Can this method of finding the Y point in 3D plane (Electro-magnetic wave propagation) be imnplemented in the same way?
you're welcome. You can use the same collection of points "Graph2DPoints" as the source for your 3dplane polyline object + use a scale transform (scaleY = -1) along with a Skew transform as RenderTransform and set (0.5 , 0.5) as the transformOrigin.
Ah, OK, I understand in which way I must implement these functions. Thanks :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.