Advertisement
WarPie90

MinAreaCircle - December 2024 version

Dec 17th, 2024
43
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 3.93 KB | None | 0 0
  1. program new;
  2.  
  3. var
  4.   img: TImage;
  5.   TPA: TPointArray;
  6.   c: TCircle;
  7.  
  8.  
  9. function TPointArray.FurthestPoint(from: TPoint): TPoint;
  10. var i: Int32;
  11. begin
  12.   if Length(Self) = 0 then Exit;
  13.   Result := Self[0];
  14.   for i:=1 to High(Self) do
  15.     if from.DistanceTo(Self[i]) > from.DistanceTo(Result)  then
  16.       Result := Self[i];
  17. end;
  18.  
  19. function Circle3(P1,P2,P3: TPoint): TCircle;
  20. var
  21.   t,d,l: Single;
  22.   p,pcs,q,qcs: record x,y: Single; end;
  23. begin
  24.   t   := ArcTan2(p1.y-p2.y, p1.x-p2.x) - PI/2;
  25.   p   := [(p1.x+p2.x) / 2, (p1.y+p2.y) / 2];
  26.   pcs := [Cos(t), Sin(t)];
  27.  
  28.   t   := ArcTan2(p1.y-p3.y, p1.x-p3.x) - PI/2;
  29.   q   := [(p1.x+p3.x) / 2, (p1.y+p3.y) / 2];
  30.   qcs := [Cos(t), Sin(t)];
  31.  
  32.   d := pcs.x * qcs.y - pcs.y * qcs.x;
  33.   if Abs(d) < 0.001 then Exit();
  34.   l := (qcs.x * (p.y - q.y) - qcs.y * (p.x - q.x)) / d;
  35.   Result.x := Round(p.x + l * pcs.x);
  36.   Result.y := Round(p.y + l * pcs.y);
  37.   Result.Radius := Ceil(Sqrt(Sqr((p.x + l * pcs.x)-p1.x) + Sqr((p.y + l * pcs.y)-p1.y)));
  38. end;
  39.  
  40.  
  41. (*
  42.   Smallest bounding circle algorithm by Slacky
  43.   https://en.wikipedia.org/wiki/Smallest-circle_problem
  44.  
  45.   Time complexity: O(max(n log n, h^2))
  46.  
  47.   Where `h` is the length of the convex hull, and `n` is the data size.
  48.   Can be guaranteed O(n log n) with rotating calipers algorithm for FurthestPoints,
  49.   dont think it's worth the added complexity though.
  50. *)
  51. function TPointArray.MinAreaCircle2(): TCircle;
  52. var
  53.   poly: TPointArray;
  54.   p1,p2,p3,p,q,t: TPoint;
  55.  
  56.   function Circle3(const P1,P2,P3: TPoint): TCircle;
  57.   var
  58.     t,d,l: Single;
  59.     p,pcs,q,qcs: record x,y: Single; end;
  60.   begin
  61.     t   := ArcTan2(p1.y-p2.y, p1.x-p2.x) - PI/2;
  62.     p   := [(p1.x+p2.x) / 2, (p1.y+p2.y) / 2];
  63.     pcs := [Cos(t), Sin(t)];
  64.  
  65.     t   := ArcTan2(p1.y-p3.y, p1.x-p3.x) - PI/2;
  66.     q   := [(p1.x+p3.x) / 2, (p1.y+p3.y) / 2];
  67.     qcs := [Cos(t), Sin(t)];
  68.  
  69.     d := pcs.x * qcs.y - pcs.y * qcs.x;
  70.     if Abs(d) < 0.001 then Exit();
  71.     l := (qcs.x * (p.y - q.y) - qcs.y * (p.x - q.x)) / d;
  72.     Result.x := Round(p.x + l * pcs.x);
  73.     Result.y := Round(p.y + l * pcs.y);
  74.     Result.Radius := Ceil(Sqrt(Sqr((p.x + l * pcs.x)-p1.x) + Sqr((p.y + l * pcs.y)-p1.y)));
  75.   end;
  76.  
  77. begin
  78.   poly := Self.ConvexHull();  // O(n log n)
  79.   poly.FurthestPoints(p1,p2); // O(m^2) call - ugh
  80.  
  81.   p := [(p1.x+p2.x) div 2, (p1.y+p2.y) div 2];
  82.   t := poly.FurthestPoint(p);
  83.  
  84.   // Two Point Circle
  85.   if (p1 = t) or (p2 = t) then
  86.     Exit([p.x,p.y, Ceil( p1.DistanceTo(p2) / 2 )]);
  87.  
  88.   // Three Point Circle
  89.   p := Circle3(p1, p2, t).Center;
  90.   q := poly.FurthestPoint(p);
  91.  
  92.   if Sign(CrossProduct(q,  p1, p2)) = Sign(CrossProduct(t, p1, p2)) then
  93.     p3 := q
  94.   else
  95.     p3 := t;
  96.  
  97.   p := Circle3(p1,p2,p3).Center;
  98.   q := poly.FurthestPoint(p);
  99.   if (p1 <> q) and (p2 <> q) and (p3 <> q) then
  100.   begin
  101.     p := [(p3.x+q.x) div 2, (p3.y+q.y) div 2];
  102.     if p1.DistanceTo(p) < p2.DistanceTo(p) then
  103.     begin
  104.       p1 := q;
  105.       Swap(p1, p2);
  106.     end else
  107.       p2 := q;
  108.  
  109.     p := Circle3(p1, p2, p3).Center;
  110.     q := poly.FurthestPoint(p);
  111.     if (p1 <> q) and (p2 <> q) and (p3 <> q) then
  112.       p1 := q;
  113.   end;
  114.  
  115.   Result := Circle3(p1, p2, p3);
  116. end;
  117.  
  118. function TPointArray.ToString(): string;
  119. var p: TPoint;
  120. begin
  121.   Result += '[';
  122.   for p in self do
  123.     Result += '['+ToString(p.x)+','+ToString(p.y)+'],';
  124.   SetLength(Result, Length(Result)-1);
  125.   Result += ']';
  126. end;
  127.  
  128. var
  129.   i: Int32;
  130.   poly: TPointArray;
  131.   c1,c2: TCircle;
  132.   p: TPoint;
  133. begin
  134.   img := TImage.Create(900,900);
  135.   img.Show(False);
  136.   RandSeed := 12345;
  137.   Writeln(RandSeed);
  138.  
  139.   i := 0;
  140.   while True do
  141.   begin
  142.     TPA := RandomTPA(50, [250,250,550,550]);
  143.  
  144.     img.DrawColor := $FF;
  145.     img.DrawPolygon(TPA.ConvexHull());
  146.  
  147.     c2 := TPA.MinAreaCircle2();
  148.     img.DrawColor := $FFFF00;
  149.     img.DrawCircle(c2.Center, c2.Radius);
  150.  
  151.     img.DrawColor := $FF;
  152.     img.DrawPolygon(TPA.ConvexHull());
  153.  
  154.  
  155.     img.Show(False);
  156.     img.Clear();
  157.  
  158.     Inc(i);
  159.   end;
  160.  
  161.   img.Show(False);
  162. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement