//************************************************************
        //       W e i g h t e d    A v e r a g e
        //************************************************************
        static float WeightedAverage(ref ScatteredData Data)

        // function calculates the weighted average value for the
        // specified grid point. The needed data is all in PointInOctant
        // and PointDistSquared.


        {
            float SumSquared = 0.0f;
            float SumWeights = 0.0f;

            for (int i = 0; i < 8; i++)
            {
                long Point = PointInOctant[i];
                if (Point > -1)
                {
                    float DistanceSquared = PointDistSquared[i];
                    // Check for point right on a grid intersection.
                    if (DistanceSquared == 0.0)
                    {
                        return(Data.Z[Point]);
                    }
                    SumSquared += 1.0f / DistanceSquared;
                    SumWeights += (1.0f / DistanceSquared) * Data.Z[Point];
                }
            }
            return(SumWeights / SumSquared);
        }
        //***************************************************************
        //            X p a n d   I n i t
        //***************************************************************
        void XpandInit(ref SurfaceGrid Zgrid, ref ScatteredData Data)
        {
            NumXcoords = Convert.ToInt32(Zgrid.xsize);
            NumYcoords = Convert.ToInt32(Zgrid.ysize);

            TotalGridPoints = (long)NumXcoords * (long)NumYcoords;
            xIndex          = yIndex = 0;
            NumberDone      = TotalRange = TotalShells = 0;
            NumDataPoints   = Data.Size;
            if (NumDataPoints < 3)
            {
                return;
            }

            xGridMin = Zgrid.x(0);
            xGridMax = Zgrid.x(NumXcoords - 1);
            yGridMin = Zgrid.y(0);
            yGridMax = Zgrid.y(NumYcoords - 1);
            float xRange      = Data.xMax - Data.xMin;
            float yRange      = Data.yMax - Data.yMin;
            float Volume      = xRange * yRange;
            float VolPerPoint = Volume / ((float)NumDataPoints / (float)nSample);

            Radius          = (float)Math.Sqrt(VolPerPoint / Math.PI);
            Diameter        = Radius * 2;
            DiameterSq      = Diameter * Diameter;
            xyStopDistSq    = DiameterSq * DensityStopRatio * DensityStopRatio;
            EdgeSenseDistSq = DiameterSq * EdgeSenseFactor * EdgeSenseFactor;

            LocateInit(ref Data, ref Zgrid);
        }
 //**************************************************************
 //        X p a n d
 //                     Generate the entire grid in one call.
 //*************************************************************
 public Xpand(ref SurfaceGrid Zgrid, ref ScatteredData RandomData)
 {
     XpandInit(ref Zgrid, ref RandomData);
     while (XpandPoint(ref Zgrid, ref RandomData))
     {
         ;
     }
 }
        //****************************************************************
        //                 P u t   I n    O c t a n t
        //****************************************************************
        static void PutInOctant(float x, float y, ref ScatteredData Data, long DataIndex)
        {
            float Xdistance = Data.X[DataIndex] - x;
            float Ydistance = Data.Y[DataIndex] - y;

            // Select the octant the data point is in. They are labeled:
            //        31
            //       2  0
            //       6  4
            //        75

            int Octant = 0;

            if (Ydistance < 0.0)
            {
                Octant = 4;
            }
            if (Xdistance < 0.0)
            {
                Octant += 2;
            }
            if (Math.Abs(Xdistance) < Math.Abs(Ydistance))
            {
                Octant += 1;
            }

            // and get the distance squared and save that information
            // for that Octant iff this is the first point found or closer than
            // the point previously saved for that octant.

            float DistSquared = Xdistance * Xdistance + Ydistance * Ydistance;

            if (NoFound == 0)
            {
                ClosestSquared = DistSquared;
            }
            if (DistSquared < ClosestSquared)
            {
                ClosestSquared = DistSquared;
            }
            NoFound++;

            if (PointInOctant[Octant] == -1 ||
                DistSquared < PointDistSquared[Octant])
            {
                PointInOctant[Octant]    = DataIndex;
                PointDistSquared[Octant] = DistSquared;
            }
        }
        //**************************************************************
        //             L o c a t e    I n i t
        //**************************************************************
        static void LocateInit(ref ScatteredData Data, ref SurfaceGrid Grid)
        {
            int ix = 0, iy = 0;

            Locator.New(NumDataPoints, NumXcoords, NumYcoords);

            for (long i = 0; i < NumDataPoints; i += nSample)
            {
                if (LocateGridX(ref ix, ref iy, Data.X[i], Data.Y[i], ref Grid))
                {
                    Locator.setnext(i, ix, iy);
                }
            }
            Locator.Sort();
        }
        //**********************************************************************
        //             S c a n    O n e   G r i d
        //**********************************************************************
        static void ScanOneGrid(int i, int j, ref ScatteredData Data, ref SurfaceGrid Grid)
        {
            long GotOne;

            for (int n = 0; true; n++)
            {
                GotOne = Locator.Search(i, j, n);
                if (GotOne < 0)
                {
                    return;
                }
                PutInOctant(Grid.x(xIndex), Grid.y(yIndex), ref Data, GotOne);
                TotalRange++;
            }
        }
        //******************************************************************
        //                    X p a n d   P o i n t
        //
        //  Evaluates one grid intersection only and advances indexes so
        //       the next call will evaluate the next one.
        //******************************************************************
        bool XpandPoint(ref SurfaceGrid Zgrid, ref ScatteredData RandomData)
        {
            float Zvalue;

            //assert( xIndex < NumXcoords );
            //assert( yIndex < NumYcoords );
            if (NumDataPoints < 3)
            {
                return(false);
            }

            // Select the closest point in each octant surround the grid point.
            SelectPoints(ref RandomData, ref Zgrid);

            // Check if point can be included and if so.. calculate it.
            if (IncludeGridPoint() > 0)
            {
                Zvalue = WeightedAverage(ref RandomData);
            }
            else
            {
                Zvalue = UndefinedZ;
            }

            Zgrid.zset(xIndex, yIndex, Zvalue);

            // Move to next grid intersection....
            ++xIndex;
            if (xIndex >= NumXcoords)
            {
                ++yIndex; xIndex = 0;
            }

            if (yIndex >= NumYcoords)
            {
                Locator.New(0, NumXcoords, NumYcoords); return(false);
            }
            ++NumberDone;
            //assert( NumberDone <= TotalGridPoints);

            return(true);
        }
        // ***************************************************************
        //                    S e l e c t    P o i n t s
        //*****************************************************************
        static void SelectPoints(ref ScatteredData Data, ref SurfaceGrid Grid)

        // This routine will search the array of Data points looking for
        // the closest point in each of the 8 octants surrounding the grid
        // coordinate currently being evaluated (at location x, y).

        {
            int Start,
                End,
                Row,
                Column;

            float TestDist;

            bool TopDone    = false;   // These are logical flags controlling the
            bool BottomDone = false;   // Shelling process.
            bool LeftDone   = false;
            bool RightDone  = false;
            int  i;

            // Zero out the arrays which keep track of closest point and its distance.
            for (i = 0; i < 8; i++)
            {
                PointInOctant[i]    = -1;
                PointDistSquared[i] = 0.0f;
            }
            NoFound = 0;

            ScanOneGrid(xIndex, yIndex, ref Data, ref Grid); // Do home grid first.

            for (int shell = 1; true; shell++)               // Now shell outwards from home.
            {
                Start = xIndex - shell; if (Start < 0)
                {
                    Start = 0;                                    // Thanks to Matt Gessner
                }
                End = xIndex + shell + 1; if (End > NumXcoords)
                {
                    End = NumXcoords;
                }
                // Do top row.
                if (!TopDone)
                {
                    Row = yIndex + shell;
                    if (Row >= NumYcoords)
                    {
                        TopDone = true;
                    }
                    else
                    {
                        TestDist = Grid.y(Row) - Grid.y(yIndex);
                        TestDist = TestDist * TestDist;
                        if (((NoFound > 0) && ((TestDist > ClosestSquared * ScanStopRatio)) ||
                             (TestDist > xyStopDistSq)))
                        {
                            TopDone = true;
                        }
                        else
                        {
                            for (i = Start; i < End; i++)
                            {
                                ScanOneGrid(i, Row, ref Data, ref Grid);
                            }
                        }
                    }
                }

                // Do bottom row.
                if (!BottomDone)
                {
                    Row = yIndex - shell;
                    if (Row < 0)
                    {
                        BottomDone = true;
                    }
                    else
                    {
                        TestDist = Grid.y(yIndex) - Grid.y(Row);
                        TestDist = TestDist * TestDist;
                        if (((NoFound > 0) && ((TestDist > ClosestSquared * ScanStopRatio)) ||
                             (TestDist > xyStopDistSq)))
                        {
                            BottomDone = true;
                        }
                        else
                        {
                            for (i = Start; i < End; i++)
                            {
                                ScanOneGrid(i, Row, ref Data, ref Grid);
                            }
                        }
                    }
                }

                Start = yIndex - shell + 1; if (Start < 0)
                {
                    Start = 0;                                        // Thanks to Matt Gessner
                }
                End = yIndex + shell; if (End > NumYcoords)
                {
                    End = NumYcoords;
                }
                // Do left column.
                if (!LeftDone)
                {
                    Column = xIndex - shell;
                    if (Column < 0)
                    {
                        LeftDone = true;
                    }
                    else
                    {
                        TestDist = Grid.x(xIndex) - Grid.x(Column);
                        TestDist = TestDist * TestDist;
                        if (((NoFound > 0) && ((TestDist > ClosestSquared * ScanStopRatio)) ||
                             (TestDist > xyStopDistSq)))
                        {
                            LeftDone = true;
                        }
                        else
                        {
                            for (i = Start; i < End; i++)
                            {
                                ScanOneGrid(Column, i, ref Data, ref Grid);
                            }
                        }
                    }
                }
                // Do right column.
                if (!RightDone)
                {
                    Column = xIndex + shell;
                    if (Column >= NumXcoords)
                    {
                        RightDone = true;
                    }
                    else
                    {
                        TestDist = Grid.x(Column) - Grid.x(xIndex);
                        TestDist = TestDist * TestDist;
                        if (((NoFound > 0) && ((TestDist > ClosestSquared * ScanStopRatio)) ||
                             (TestDist > xyStopDistSq)))
                        {
                            RightDone = true;
                        }
                        else
                        {
                            for (i = Start; i < End; i++)
                            {
                                ScanOneGrid(Column, i, ref Data, ref Grid);
                            }
                        }
                    }
                }
                if (TopDone && BottomDone && LeftDone && RightDone)
                {
                    TotalShells += shell; break;
                }
            }
        }