//************************************************************ // 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; } } }