using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Media.Media3D;
using System.Diagnostics;


namespace Generate3DMesh
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>

    // Example 17-27. Adding a generated model to the view
    public partial class Window1 : Window
    {
        double[,] points;

        public Window1()
        {
            InitializeComponent();

            points = GraphDataBuilder.BuildSincFunction(100, 100, 2.5, 5);
            ModelVisual3D vis3D = BuildModelVisual3DFromPoints(points);
            modelHost.Children.Add(vis3D);

            vp.MouseMove += myViewport_MouseMove;
        }


        // Example 17-29. Creating the ModelVisual3D

        static ModelVisual3D BuildModelVisual3DFromPoints(double[,] points)
        {
            MeshGeometry3D mesh = MeshBuilder.BuildMeshFromPoints(points, 1, 1);
            GeometryModel3D model = BuildModel3DFromMesh(mesh);
            ModelVisual3D vis3D = new ModelVisual3D();
            vis3D.Transform = new MatrixTransform3D(new Matrix3D(1, 0, 0, 0,
                0, 0, 1, 0,
                0, 0.1, 0, 0,
                0, 0, 0, 1));
            vis3D.Content = model;
            return vis3D;
        }

        // End of Example 17-29.


        // Example 17-32. Creating a GeometryModel3D

        private static GeometryModel3D BuildModel3DFromMesh(MeshGeometry3D mesh)
        {
            Material front = new DiffuseMaterial(Brushes.Red);
            GeometryModel3D model = new GeometryModel3D(mesh, front);
            model.BackMaterial = new DiffuseMaterial(Brushes.Green);
            return model;
        }

        // End of Example 17-32.


        // Example 17-33. Hit testing with a 2D starting point

        void myViewport_MouseMove(object sender, MouseEventArgs e)
        {
            Point mousePos = e.GetPosition(vp);
            PointHitTestParameters hitParams = new PointHitTestParameters(mousePos);
            VisualTreeHelper.HitTest(vp, null, delegate(HitTestResult hr)
            {
                RayMeshGeometry3DHitTestResult rayHit = hr as
                       RayMeshGeometry3DHitTestResult;
                if (rayHit != null)
                {
                    Debug.WriteLine(rayHit.PointHit);

                    // Example 17-34. Extracting hit test details

                    MeshGeometry3D mesh = rayHit.MeshHit as MeshGeometry3D;
                    if (mesh != null)
                    {
                        int pointsWidth = points.GetLength(0);
                        int y = rayHit.VertexIndex1 / pointsWidth;
                        int x = rayHit.VertexIndex1 - (y * pointsWidth);

                        Debug.WriteLine(string.Format("Point: {0},{1} value = {2}",
                            x, y, points[x, y]));


                        // Example 17-35. Calculating the exact hit position

                        Point3D pointInMesh1 = mesh.Positions[rayHit.VertexIndex1];
                        Point3D pointInMesh2 = mesh.Positions[rayHit.VertexIndex2];
                        Point3D pointInMesh3 = mesh.Positions[rayHit.VertexIndex3];
                        double xf = pointInMesh1.X * rayHit.VertexWeight1 +
                                   pointInMesh2.X * rayHit.VertexWeight2 +
                                   pointInMesh3.X * rayHit.VertexWeight3;
                        double yf = pointInMesh1.Y * rayHit.VertexWeight1 +
                                   pointInMesh2.Y * rayHit.VertexWeight2 +
                                   pointInMesh3.Y * rayHit.VertexWeight3;
                        double zf = pointInMesh1.Z * rayHit.VertexWeight1 +
                                   pointInMesh2.Z * rayHit.VertexWeight2 +
                                   pointInMesh3.Z * rayHit.VertexWeight3;

                        Point3D exactLocation = new Point3D(xf, yf, zf);

                        // End of Example 17-35.

                        Debug.WriteLine("Exact: " + exactLocation);

                    }

                    // End of Example 17-34.
                }
                return HitTestResultBehavior.Continue;
            }, hitParams);
        }

        // End of Example 17-33.
    }

    // End of Example 17-27.
}