Janilabo

Function Version

Aug 23rd, 2013
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pascal 6.67 KB | None | 0 0
  1. {==============================================================================]
  2.  Splits TPA with minDist, maxDist.
  3. [==============================================================================}
  4. function TPADistributeEx(TPA: TPointArray; minDist, maxDist: Extended): T2DPointArray;
  5. var
  6.   h, i, l, c, s, x, y, o, r, d, m: Integer;
  7.   p: T2DIntegerArray;
  8.   q: TPointArray;
  9.   a, b: TBox;
  10.   e: Extended;
  11.   z: TPoint;
  12. begin
  13.   SetLength(Result, 0);
  14.   h := High(TPA);
  15.   if ((minDist <= maxDist) and (h > -1)) then
  16.     if (h > 0) then // We make sure array is bigger than 1 item...
  17.     begin
  18.       b.X1 := TPA[0].X; // START: Capturing bounds of TPA
  19.       b.Y1 := TPA[0].Y;
  20.       b.X2 := TPA[0].X;
  21.       b.Y2 := TPA[0].Y;
  22.       r := 0;
  23.       for i := 1 to h do
  24.       begin
  25.         if (TPA[i].X < b.X1) then
  26.           b.X1 := TPA[i].X
  27.         else
  28.           if (TPA[i].X > b.X2) then
  29.             b.X2 := TPA[i].X;
  30.         if (TPA[i].Y < b.Y1) then
  31.           b.Y1 := TPA[i].Y
  32.         else
  33.           if (TPA[i].Y > b.Y2) then
  34.             b.Y2 := TPA[i].Y;
  35.       end; // END: Bounds captured!
  36.       SetLength(p, ((b.X2 - b.X1) + 1)); // We create 2D Integer table, for storing point counts (if array contains duplicates). This part is the 1D.
  37.       for i := 0 to (b.X2 - b.X1) do // Creating 2D side with loop.
  38.       begin
  39.         SetLength(p[i], ((b.Y2 - b.Y1) + 1));
  40.         for c := 0 to (b.Y2 - b.Y1) do
  41.           p[i][c] := 0; // Setting 0 as default value for all array items.
  42.       end;
  43.       if (maxDist < 0.0) then // Making sure maxDist isn't lower than 0
  44.         maxDist := 0.0; // ..when it isn't, we set it to 0.
  45.       d := Ceil(maxDist); // Storing distance by maxDist to d variable, which will be used for scanning the point groups to result.
  46.       m := Max(((b.X2 - b.X1) + 1), ((b.Y2 - b.Y1) + 1)); // We get the maximum radius that we should be using.
  47.       if (d > m) then // We make sure d isn't greater than maximum radius could be in the first place.. To reduce checking a bit, when user hits with long distances that aren't even needed.
  48.         d := m;
  49.       for i := 0 to h do // We loop through whole array increasing the Integer table values with points, this we will get the point counts.
  50.         Inc(p[(TPA[i].X - b.X1)][(TPA[i].Y - b.Y1)]);
  51.       for i := 0 to h do
  52.         if (p[(TPA[i].X - b.X1)][(TPA[i].Y - b.Y1)] > 0) then // Time to start capturing the groups
  53.         begin
  54.           c := Length(Result);
  55.           SetLength(Result, (c + 1)); // Creating first/next group of points for result.
  56.           SetLength(Result[c], p[(TPA[i].X - b.X1)][(TPA[i].Y - b.Y1)]); // We set the length for all points at this coordinate, by point count.
  57.           for o := 0 to (p[(TPA[i].X - b.X1)][(TPA[i].Y - b.Y1)] - 1) do // Loop for planting all the points from current TPA index to this new group.
  58.             Result[c][o] := TPA[i];
  59.           SetLength(q, 1); // Creating new queue
  60.           q[0] := TPA[i]; // ..we set the current TPA item as the object for it...
  61.           r := (r + p[(TPA[i].X - b.X1)][(TPA[i].Y - b.Y1)]); // R variable is for keeping track of points that we have "met" so far, this part increases it by the total points
  62.           if (r > h) then // We can simply exit, there's no more to go through, because there was so many duplicates in the array, probably.
  63.             Exit;
  64.           p[(TPA[i].X - b.X1)][(TPA[i].Y - b.Y1)] := 0; // Setting the point count to 0, that way we don't hit the same place twice, which would fuck up things pretty bad!
  65.           s := 1; // Simply needed for the while..do loop to work.
  66.           while (s > 0) do // While there's still queue items to check through...
  67.           begin
  68.             s := High(q); // Highest queue
  69.             z := q[s]; // Storing the point to Z variable for checking.
  70.             a.X1 := (z.X - d); // Creating the area from point Z (by QUEUE) with radius, for scanning the points.
  71.             a.Y1 := (z.Y - d);
  72.             a.X2 := (z.X + d);
  73.             a.Y2 := (z.Y + d);
  74.             SetLength(q, s); // We decrease queue by 1, pretty much.
  75.             if (a.X1 < b.X1) then // START: Lets constrain TBox a (scan area) to the boundaries of b, which is the variable for our TPA bounds.
  76.               a.X1 := b.X1
  77.             else
  78.               if (a.X1 > b.X2) then
  79.                 a.X1 := b.X2;
  80.             if (a.Y1 < b.Y1) then
  81.               a.Y1 := b.Y1
  82.             else
  83.               if (a.Y1 > b.Y2) then
  84.                 a.Y1 := b.Y2;
  85.             if (a.X2 < b.X1) then
  86.               a.X2 := b.X1
  87.             else
  88.               if (a.X2 > b.X2) then
  89.                 a.X2 := b.X2;
  90.             if (a.Y2 < b.Y1) then
  91.               a.Y2 := b.Y1
  92.             else
  93.               if (a.Y2 > b.Y2) then
  94.                 a.Y2 := b.Y2; // END: DONE! This way, there's no looping outside the bounds, speeds up things.
  95.             for x := a.X1 to a.X2 do // Lets loop through area for new points to group.
  96.               for y := a.Y1 to a.Y2 do
  97.                 if (p[(x - b.X1)][(y - b.Y1)] > 0) then // When we hit Integer table slot which contains more than 0 points, we possibly hitted a match... Time to capture the point(s)!
  98.                 begin
  99.                   e := Sqrt(Sqr(z.X - x) + Sqr(z.Y - y)); // Calculating the distance between Z (center point) and this new point from table.
  100.                   if ((e >= minDist) and (e <= maxDist)) then // ..and if it's within minDist and maxDist, we take it in, else we will leave it, because its not valid.
  101.                   begin
  102.                     l := Length(Result[c]);
  103.                     SetLength(Result[c], (l + p[(x - b.X1)][(y - b.Y1)])); // Once again, capturing the point(s) to group, pretty much the same actions as with the first group item.
  104.                     for o := 0 to (p[(x - b.X1)][(y - b.Y1)] - 1) do
  105.                     begin
  106.                       Result[c][(l + o)].X := x;
  107.                       Result[c][(l + o)].Y := y;
  108.                     end;
  109.                     r := (r + p[(x - b.X1)][(y - b.Y1)]);
  110.                     if (r > h) then
  111.                       Exit;
  112.                     p[(x - b.X1)][(y - b.Y1)] := 0;
  113.                     SetLength(q, (s + 1));
  114.                     q[s] := Result[c][l]; // Added the point to checking/scanning queu.
  115.                     Inc(s);
  116.                   end;
  117.                 end;
  118.           end;
  119.         end;
  120.     end else
  121.     begin // When we have only 1 point, there's no need to do any looping, so lets just create the array simply this easy way...
  122.       SetLength(Result, 1);
  123.       SetLength(Result[0], 1);
  124.       Result[0][0] := TPA[0];
  125.     end;
  126. end;
  127.  
  128. function TPADistribute(TPA: TPointArray; dist: Extended): T2DPointArray;
  129. begin
  130.   Result := TPADistributeEx(TPA, 0, dist);
  131. end;
Advertisement
Add Comment
Please, Sign In to add comment