Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- program new;
- (*
- Generates a random point within the (convex)polygon/quad/triangle, drawn towards a Target point.
- Parameters:
- * Target: The point towards which the distribution is drawn.
- * weight: Controls the strength of attraction towards the Target (higher values = stronger attraction).
- - weight = 0 gives a uniform distribution.
- * bias: Introduces a Gaussian spread around the Target (higher values = wider spread).
- - bias = 0 gives a purely weighted distribution towards the Target.
- Should expose weight and bias to the user if used as mouse distribution method. weight of 10 might be a little high.
- *)
- function PolygonNearestEdge(Polygon: TPointArray; P: TPoint): TPoint;
- var
- dist, best: single;
- I: Integer;
- q: TPoint;
- begin
- Best := $FFFFFF;
- Result := Polygon[0];
- for I := 0 to High(Polygon) do
- begin
- dist := DistToLine(p, Polygon[i], Polygon[(i+1) mod Length(Polygon)], q);
- if (dist < best) then
- begin
- Best := dist;
- Result := q;
- end;
- end;
- end;
- function TTriangle.RandomWeightedPoint(Target: TPoint; weight: Single=10.0; bias: Single=1): TPoint;
- var
- r1, r2, r3, u, v, w, t, sum: Single;
- stdev,xr,yr: Single;
- const
- eps := 0.0000001;
- begin
- if bias > 0 then
- begin
- xr := abs(Self.A.x - Target.x) + abs(Self.B.x - Target.x) + abs(Self.C.x - Target.x);
- yr := abs(Self.A.y - Target.y) + abs(Self.B.y - Target.y) + abs(Self.C.x - Target.y);
- Target.X += Round(GaussRand(0, xr/3 * bias) / weight);
- Target.Y += Round(GaussRand(0, yr/3 * bias) / weight);
- end;
- if not (Target in Self) then
- Target := Self.NearestEdge(Target);
- r1 := Random();
- r2 := Random();
- if r1 + r2 > 1 then
- begin
- r1 := 1 - r1;
- r2 := 1 - r2;
- end;
- r3 := Random();
- sum := (r1 + r2 + (1 - r1 - r2) + weight * r3) + eps;
- u := r1 / sum;
- v := r2 / sum;
- w := (1 - r1 - r2) / sum;
- t := (weight * r3) / sum;
- with Self do
- begin
- Result.X := Round(u * A.X + v * B.X + w * C.X + t * Target.X);
- Result.Y := Round(u * A.Y + v * B.Y + w * C.Y + t * Target.Y);
- end;
- end;
- // do a polygon type or.. just rename to PolygonR...
- function TPointArray.RandomWeightedPoint(Target: TPoint; weight: Single=10.0; bias: Single=1): TPoint;
- var
- i: Integer;
- tri: TTriangleArray;
- xr,yr,b,sum, r, stdev, area: Single;
- begin
- area := PolygonArea(Self);
- if bias > 0 then
- begin
- for i := 0 to High(Self) do xr += abs(Self[i].x - Target.x);
- xr /= Length(self);
- for i := 0 to High(Self) do yr += abs(Self[i].y - Target.y);
- yr /= Length(self);
- Target.X += Round(GaussRand(0, xr * bias) / weight);
- Target.Y += Round(GaussRand(0, yr * bias) / weight);
- end;
- if not PointInPolygon(Target, Self) then
- Target := PolygonNearestEdge(Self,Target);
- for i := 0 to High(Self) do
- tri += TTriangle.Create(Target, Self[i], Self[(i+1) mod Length(Self)]);
- r := Random() * area;
- sum := 0;
- for i := 0 to High(tri) do
- begin
- sum += tri[i].Area;
- if r < sum then
- Exit(tri[i].RandomWeightedPoint(Target, weight, 0));
- end;
- end;
- function TQuad.RandomWeightedPoint(Target: TPoint; weight: Single=10.0; bias: Single=1): TPoint;
- begin
- Result := Self.Corners.RandomWeightedPoint(Target, weight, bias);
- end;
- var
- t, p: TPoint;
- Tri: TTriangle;
- Image: TImage;
- hsl: TColorHSL;
- mat: TSingleMatrix;
- weight: Single := 10.0;
- pts,poly: TPointArray;
- begin
- Tri := [[100,200],[800,100],[700,400]];
- pts := RandomTPA(7, [200,200,500,500]);
- poly := pts.ConvexHull();
- Writeln(poly);
- Image := TImage.Create(800,800);
- Image.DrawPolygon(tri.Corners);
- Image.Show();
- while True do
- begin
- SetLength(mat, 0,0);
- mat.SetSize(800,800);
- t := Target.MouseXY;
- for 0 to 20000 do
- begin
- p := Tri.RandomWeightedPoint(T, weight, 0.5);
- if Image.InImage(p.x-1,p.y-1) and Image.InImage(p.x+1,p.y+1) then
- begin
- mat[p.y+1,p.x] += 1;
- mat[p.y-1,p.x] += 1;
- mat[p.y,p.x+1] += 1;
- mat[p.y,p.x-1] += 1;
- mat[p.y,p.x] += 1;
- end;
- end;
- WriteLn(weight);
- if Target.MousePressed(EMouseButton.LEFT) then weight += 0.1;
- if Target.MousePressed(EMouseButton.Right) then weight -= 0.1;
- Image.FromMatrix(mat);
- Image.DrawPolygon(Tri.Corners);
- Image.Show(False);
- end;
- end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement