Advertisement
WarPie90

Simba 1.5 simple concave hull

Sep 24th, 2023 (edited)
1,900
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 4.89 KB | None | 0 0
  1. program new;
  2.  
  3. function DouglasPeucker(TPA: TPointArray; epsilon:Double): TPointArray;
  4. var
  5.   L, i, index: Int32;
  6.   dmax, d: Double;
  7.   Slice1,Slice2: TPointArray;
  8. begin
  9.   L := Length(TPA);
  10.   if L = 0 then Exit;
  11.  
  12.   for i:=1 to High(TPA) do
  13.   begin
  14.     d := DistToLine(TPA[i], TPA[0], TPA[High(TPA)]);
  15.     if ( d > dmax ) then
  16.     begin
  17.       index := i;
  18.       dmax  := d;
  19.     end;
  20.   end;
  21.  
  22.   if (dmax > epsilon) then
  23.   begin
  24.     Slice1 := DouglasPeucker(Copy(TPA, 0, index), epsilon);
  25.     Slice2 := DouglasPeucker(Copy(TPA, index), epsilon);
  26.  
  27.     Result := Slice1;
  28.     Result += Slice2;
  29.   end else
  30.     Result := [TPA[0], TPA[High(TPA)]];
  31. end;
  32.  
  33.  
  34. (*
  35.   Concave hull approximation using range query based on given distance "MaxLeap".
  36.   if maxleap doesn't cover all of the input then several output polygons will be created.
  37.   MaxLeap is by default automatically calulcated by the density of the polygon
  38.   described by convexhull. But can be changed.
  39.  
  40.   Higher maxleap is slower.
  41.   Epsilon describes how accurate you want your output, and have some impact on speed.
  42. *)
  43. function ConcaveHullEx(TPA: TPointArray; MaxLeap: Double=-1; Epsilon:Double=2): T2DPointArray;
  44. var
  45.   res, pts, poly: TPointArray;
  46.   tree: TSlackTree;
  47.   i,c: Int32;
  48.   B: TBox;
  49. begin
  50.   B := TPA.Bounds();
  51.   TPA := TPA.PartitionEx([B.X1-Round(Epsilon), B.y1-Round(Epsilon)], Round(Epsilon*2-1), Round(Epsilon*2-1)).Means();
  52.   if Length(TPA) <= 2 then Exit([TPA]);
  53.   tree.Init(TPA);
  54.  
  55.   if MaxLeap = -1 then
  56.     MaxLeap := Ceil(Sqrt(PolygonArea(TPA.ConvexHull()) / TPA.Length())*Sqrt(2));
  57.  
  58.   MaxLeap := Max(MaxLeap, Epsilon*2);
  59.   SetLength(res, 256);
  60.   for i:=0 to High(tree.data) do
  61.   begin
  62.     pts := tree.RangeQueryEx(tree.data[i].split, MaxLeap,MaxLeap, False);
  63.  
  64.     if Length(pts) <= 1 then continue;
  65.     pts := pts.ConvexHull().Connect();
  66.  
  67.     if Length(pts)+c >= Length(res) then
  68.       SetLength(res, Max(c*2, c+Length(pts)));
  69.     Move(pts[0], res[c], Length(pts)*SizeOf(TPoint));
  70.  
  71.     Inc(c, Length(pts));
  72.   end;
  73.  
  74.   SetLength(pts, c);
  75.   pts := pts.Unique(); //not needed, but might be faster
  76.   for pts in res.Cluster(2) do
  77.     Result += DouglasPeucker(pts.Border(), Epsilon);
  78. end;
  79.  
  80.  
  81. (*
  82.   Concave hull approximation using k nearest neighbors
  83.   Instead of describing a specific max distance we assume that the boundary points are evenly spread out
  84.   so we can simply extract a number of neighbors and connect the hull of those.
  85.   Worst case it cuts off points.
  86.  
  87.   Will reduce the TPA to a simpler shape if it's dense, defined by epsilon.
  88.  
  89.   If areas are cut off, you have two options based on your needs:
  90.   1. Increase "Epsilon", this will reduce accurate.. But it's faster.
  91.   2. Increase "kCount", this will maintain accuracy.. But it's slower.
  92. *)
  93. function ConcaveHull(TPA: TPointArray; Epsilon:Double=2.5; kCount:Int32=5): TPointArray;
  94. var
  95.   res, pts, poly: TPointArray;
  96.   tree: TSlackTree;
  97.   i,c: Int32;
  98.   B: TBox;
  99. begin
  100.   B := TPA.Bounds();
  101.   TPA := TPA.PartitionEx([B.X1-Round(Epsilon), B.y1-Round(Epsilon)], Round(Epsilon*2-1), Round(Epsilon*2-1)).Means();
  102.   if Length(TPA) <= 2 then Exit(TPA);
  103.   tree.Init(TPA);
  104.  
  105.   SetLength(res, 256);
  106.   for i:=0 to High(tree.data) do
  107.   begin
  108.     pts := tree.KNearest(tree.data[i].split, kCount, False);
  109.     //tree.data[i].hidden := True;
  110.  
  111.     if Length(pts) <= 1 then continue;
  112.     pts := pts.ConvexHull().Connect();
  113.  
  114.     if Length(pts)+c >= Length(res) then
  115.       SetLength(res, Max(c*2, c+Length(pts)));
  116.     Move(pts[0], res[c], Length(pts)*SizeOf(TPoint));
  117.  
  118.     Inc(c, Length(pts));
  119.   end;
  120.  
  121.   SetLength(res, c);
  122.  
  123.   Result := DouglasPeucker(res.Border(), Max(2,Epsilon/2));
  124. end;
  125.  
  126. procedure GenTestHullEx(bmp: TMufasaBitmap; TPA: TPointArray);
  127. var
  128.   i,j,color: Int32;
  129.   t: Double;
  130.   polys: T2DPointArray;
  131. begin
  132.   t := PerformanceTimer();
  133.   polys := ConcaveHullEx(TPA);
  134.   WriteLn PerformanceTimer() - t;
  135.  
  136.   for i:=0 to High(polys) do
  137.   begin
  138.     color := Random($FFFFFF);
  139.     bmp.DrawTPA(polys[i].Connect(), color);
  140.     for j:=0 to High(polys[i]) do BMP.DrawCircleFilled(polys[i][j], 2, color);
  141.   end;
  142. end;
  143.  
  144. procedure GenTestHull(bmp: TMufasaBitmap; TPA: TPointArray);
  145. var
  146.   i,j,color: Int32;
  147.   t: Double;
  148.   poly: TPointArray;
  149. begin
  150.   t := PerformanceTimer();
  151.   poly := ConcaveHull(TPA);
  152.   WriteLn PerformanceTimer() - t;
  153.  
  154.   color := Random($FFFFFF);
  155.   bmp.DrawTPA(poly.Connect(), color);
  156.   for j:=0 to High(poly) do BMP.DrawCircleFilled(poly[j], 2, color);
  157. end;
  158.  
  159. var
  160.   TPA,pts,poly: TPointArray;
  161.   polys: T2DPointArray;
  162.   bmp: TMufasaBitmap;
  163.   i,d,j,color: Int32;
  164.   t,x: Double;
  165.  
  166. begin
  167.   bmp := TMufasaBitmap.CreateFromFile('images/shapes.png');
  168.   TPA := bmp.Finder.FindColor(0, 90, [0,0,bmp.GetWidth()-1, bmp.GetHeight()-1]);
  169.   WriteLn(Length(TPA));
  170.   TPA := RandomTPA(10000, [50,50,850,850]);
  171.   bmp.Clear();
  172.   bmp.DrawTPA(TPA, $555555);
  173.  
  174.   GenTestHullEx(bmp, TPA);
  175.   bmp.Show();
  176.  
  177.   //GenTestHull(bmp, TPA);
  178.   //bmp.Show();
  179. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement