Advertisement
WarPie90

[Simba 2.0] Random weighted point

Jan 2nd, 2025 (edited)
1,321
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 5.27 KB | None | 0 0
  1. program new;
  2.  
  3. (*
  4.   Todo: Add force param perhaps?  
  5.  
  6.   Generates a random point within the (convex)polygon/quad/triangle, drawn towards a Target point.
  7.  
  8.   Parameters:
  9.  
  10.   * Target: The point towards which the distribution is drawn.
  11.   * weight: Controls the strength of attraction towards the Target (higher values = stronger attraction).
  12.             - weight = 0 gives a uniform distribution.
  13.   * bias:   Introduces a Gaussian spread around the Target (higher values = wider spread).
  14.             - bias = 0 gives a purely weighted distribution towards the Target.
  15.  
  16.   Should expose weight and bias to the user if used as mouse distribution method. weight of 10 might be a little high.
  17. *)
  18.  
  19. function PolygonNearestEdge(Polygon: TPointArray; P: TPoint): TPoint;
  20. var
  21.   dist, best: single;
  22.   I: Integer;
  23.   q: TPoint;
  24. begin
  25.   Best   := $FFFFFF;
  26.   Result := Polygon[0];
  27.   for I := 0 to High(Polygon) do
  28.   begin
  29.     dist := DistToLine(p, Polygon[i], Polygon[(i+1) mod Length(Polygon)], q);
  30.     if (dist < best) then
  31.     begin
  32.       Best   := dist;
  33.       Result := q;
  34.     end;
  35.   end;
  36. end;
  37.  
  38.  
  39. function TTriangle.RandomWeightedPoint(Target: TPoint; weight: Single=10.0; bias: Single=1): TPoint;
  40. var
  41.   r1, r2, r3, u, v, w, t, sum: Single;
  42.   stdev,xr,yr: Single;
  43. const
  44.   eps := 0.0000001;
  45. begin
  46.   if (bias > 0) and (weight <> 0) then
  47.   begin
  48.     xr := abs(Self.A.x - Target.x) + abs(Self.B.x - Target.x) + abs(Self.C.x - Target.x);
  49.     yr := abs(Self.A.y - Target.y) + abs(Self.B.y - Target.y) + abs(Self.C.y - Target.y);
  50.  
  51.     Target.X += Round(GaussRand(0, xr/3 * bias) / weight);
  52.     Target.Y += Round(GaussRand(0, yr/3 * bias) / weight);
  53.   end;
  54.  
  55.   if not (Target in Self) then
  56.     Target := Self.NearestEdge(Target);
  57.  
  58.   r1 := Random();
  59.   r2 := Random();
  60.   if r1 + r2 > 1 then
  61.   begin
  62.     r1 := 1 - r1;
  63.     r2 := 1 - r2;
  64.   end;
  65.  
  66.   r3 := Random();
  67.   sum := 1 + weight * r3 + eps;
  68.   u := r1 / sum;
  69.   v := r2 / sum;
  70.   w := (1 - r1 - r2) / sum;
  71.   t := (weight * r3) / sum;
  72.  
  73.   with Self do
  74.   begin
  75.     Result.X := Round(u * A.X + v * B.X + w * C.X + t * Target.X);
  76.     Result.Y := Round(u * A.Y + v * B.Y + w * C.Y + t * Target.Y);
  77.   end;
  78. end;
  79.  
  80. // do a polygon type or.. just rename to PolygonR...
  81. function TPointArray.RandomWeightedPoint(Target: TPoint; weight: Single=10.0; bias: Single=1): TPoint;
  82. var
  83.   i: Integer;
  84.   tri: TTriangleArray;
  85.   xr,yr,b,sum, r, stdev, area: Single;
  86. begin
  87.   area := PolygonArea(Self);
  88.  
  89.   if bias > 0 then
  90.   begin
  91.     for i := 0 to High(Self) do xr += abs(Self[i].x - Target.x);
  92.     xr /= Length(self);
  93.  
  94.     for i := 0 to High(Self) do yr += abs(Self[i].y - Target.y);
  95.     yr /= Length(self);
  96.  
  97.     Target.X += Round(GaussRand(0, xr * bias) / weight);
  98.     Target.Y += Round(GaussRand(0, yr * bias) / weight);
  99.   end;
  100.  
  101.   if not PointInPolygon(Target, Self) then
  102.     Target := PolygonNearestEdge(Self,Target);
  103.  
  104.   for i := 0 to High(Self) do
  105.     tri += TTriangle.Create(Target, Self[i], Self[(i+1) mod Length(Self)]);
  106.  
  107.   r := Random() * area;
  108.   sum := 0;
  109.   for i := 0 to High(tri) do
  110.   begin
  111.     sum += tri[i].Area;
  112.     if r < sum then
  113.       Exit(tri[i].RandomWeightedPoint(Target, weight, 0));
  114.   end;
  115. end;
  116.  
  117. function TQuad.RandomWeightedPoint(Target: TPoint; weight: Single=10.0; bias: Single=1): TPoint;
  118. begin
  119.   Result := Self.Corners.RandomWeightedPoint(Target, weight, bias);
  120. end;
  121.  
  122. function TCircle.RandomWeightedPoint(Target: TPoint; weight: Single = 10.0; bias: Single = 1): TPoint;
  123. var
  124.   angle, dist, r1, r2, sum, u, t: Single;
  125.   randX, randY: Single;
  126. begin
  127.   if (bias > 1) and (weight <> 0) then
  128.   begin
  129.     Target.X += Round(GaussRand(0, Self.Radius * bias / 2) / weight);
  130.     Target.Y += Round(GaussRand(0, Self.Radius * bias / 2) / weight);
  131.   end;
  132.  
  133.   if not Self.Contains(Target) then
  134.     Target := Self.PointAtDegrees(Target.AngleBetween([Self.x, Self.y]));
  135.  
  136.   angle := Random() * 2 * Pi;
  137.   dist := sqrt(Random()) * Self.Radius;
  138.   randX := Self.X + cos(angle) * dist;
  139.   randY := Self.Y + sin(angle) * dist;
  140.  
  141.   r1 := 1;
  142.   r2 := weight * Random();
  143.   sum := r1 + r2 + 0.0000001;
  144.  
  145.   u := r1 / sum;
  146.   t := r2 / sum;
  147.  
  148.   Result.X := Round(u * randX + t * Target.X);
  149.   Result.Y := Round(u * randY + t * Target.Y);
  150. end;
  151.  
  152.  
  153. var
  154.   t, p: TPoint;
  155.   Tri: TTriangle;
  156.   Image: TImage;
  157.   hsl: TColorHSL;
  158.   mat: TSingleMatrix;
  159.   weight: Single := 10.0;
  160.   pts,poly: TPointArray;
  161. begin
  162.   Tri := [[100,200],[800,100],[700,400]];
  163.  
  164.   pts  := RandomTPA(7, [200,200,500,500]);
  165.   poly := pts.ConvexHull();
  166.  
  167.   Writeln(poly);
  168.  
  169.   Image := TImage.Create(800,800);
  170.   Image.DrawPolygon(tri.Corners);
  171.   Image.Show();
  172.  
  173.   while True do
  174.   begin
  175.     SetLength(mat, 0,0);
  176.     mat.SetSize(800,800);
  177.  
  178.     t := Target.MouseXY;
  179.     for 0 to 20000 do
  180.     begin
  181.       p := Tri.RandomWeightedPoint(T, weight, 0.5);
  182.  
  183.       if Image.InImage(p.x-1,p.y-1) and Image.InImage(p.x+1,p.y+1) then
  184.       begin
  185.         mat[p.y+1,p.x] += 1;
  186.         mat[p.y-1,p.x] += 1;
  187.         mat[p.y,p.x+1] += 1;
  188.         mat[p.y,p.x-1] += 1;
  189.         mat[p.y,p.x] += 1;
  190.       end;
  191.     end;
  192.  
  193.     WriteLn(weight);
  194.  
  195.     if Target.MousePressed(EMouseButton.LEFT)  then weight += 0.1;
  196.     if Target.MousePressed(EMouseButton.Right) then weight -= 0.1;
  197.  
  198.  
  199.     Image.FromMatrix(mat);
  200.     Image.DrawPolygon(Tri.Corners);
  201.     Image.Show(False);
  202.   end;
  203. end.
  204.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement