Janilabo

TPA Polygon Development

Jul 21st, 2013
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pascal 10.66 KB | None | 0 0
  1. // Original algorithms by slacky, optimized by Janilabo
  2.  
  3. {==============================================================================]
  4.   Explanation: Returns polygon by given outlines (shape)
  5.   NOTE: Original algorithm by slacky (warpie)
  6. [==============================================================================}
  7. function TPAPolygon(shape: TPointArray): TPointArray;
  8. var
  9.   b: TBox;
  10.   x, y, h, i, l, r, z: Integer;
  11.   o: TPointArray;
  12.   f: Boolean;
  13.   t: array of TBoolArray;
  14.   e: Extended;
  15.   q, p, d: TPoint;
  16. begin
  17.   h := High(shape);
  18.   if (h > -1) then
  19.   begin
  20.     b := IntToBox(shape[0].X, shape[0].Y, shape[0].X, shape[0].Y);
  21.     for i := 0 to h do
  22.     begin
  23.       q := shape[i];
  24.       if (i < h) then
  25.         p := shape[(i + 1)]
  26.       else
  27.         p := shape[0];
  28.       r := Length(o);
  29.       if ((q.X <> p.X) or (q.Y <> p.Y)) then
  30.       begin
  31.         l := Max(Round(Abs(q.X - p.X)), Round(Abs(q.Y - p.Y)));
  32.         SetLength(o, ((r + l) + 1));
  33.         for z := 0 to l do
  34.           o[(r + z)] := Point((q.X + Round((p.X - q.X) * (z / Extended(l)))), (q.Y + Round((p.Y - q.Y) * (z / Extended(l)))));
  35.       end else
  36.       begin
  37.         SetLength(o, (r + 1));
  38.         o[r] := q;
  39.       end;
  40.       if (shape[i].X < b.X1) then
  41.         b.X1 := shape[i].X
  42.       else
  43.         if (shape[i].X > b.X2) then
  44.           b.X2 := shape[i].X;
  45.       if (shape[i].Y < b.Y1) then
  46.         b.Y1 := shape[i].Y
  47.       else
  48.         if (shape[i].Y > b.Y2) then
  49.           b.Y2 := shape[i].Y;
  50.     end;
  51.     SetLength(t, ((b.X2 - b.X1) + 1));
  52.     for i := 0 to (b.X2 - b.X1) do
  53.       SetLength(t[i], ((b.Y2 - b.Y1) + 1));
  54.     l := Length(o);
  55.     for i := 0 to (l - 1) do
  56.       if not t[(o[i].X - b.X1)][(o[i].Y - b.Y1)] then
  57.         t[(o[i].X - b.X1)][(o[i].Y - b.Y1)] := True;
  58.     SetLength(o, 0);
  59.     for y := 0 to (b.Y2 - b.Y1) do
  60.       for x := 0 to (b.X2 - b.X1) do
  61.       begin
  62.         f := t[x][y];
  63.         if not f then
  64.         begin
  65.           d := Point((x + b.X1), (y + b.Y1));
  66.           q := shape[0];
  67.           for i := 0 to (h + 1) do
  68.           begin
  69.             p := shape[(i mod (h + 1))];
  70.             if (d.Y > Min(q.Y, p.Y)) then
  71.               if (d.Y <= Max(q.Y, p.Y)) then
  72.                 if (d.X <= Max(q.X, p.X)) then
  73.                 begin
  74.                   if (q.y <> p.y) then
  75.                     e := ((d.Y - q.Y) * (p.X - q.X) / Extended((p.Y - q.Y)) + q.X);
  76.                   if ((q.X = p.X) or (d.X < e)) then
  77.                     f := not f;
  78.                 end;
  79.             q := p;
  80.           end;
  81.         end;
  82.         if f then
  83.         begin
  84.           l := Length(Result);
  85.           SetLength(Result, (l + 1));
  86.           Result[l] := Point((x + b.X1), (y + b.Y1));
  87.         end;
  88.       end;
  89.     SetLength(t, 0);
  90.   end else
  91.     SetLength(Result, 0);
  92. end;
  93.  
  94. {==============================================================================]
  95.   Explanation: Given a TPA - this function will connect each point, from first to last.
  96.   NOTE: Original algorithm by slacky (warpie)
  97. [==============================================================================}
  98. function TPAConnect(pts: TPointArray): TPointArray;
  99. var
  100.   i, j, h, l, r, a: Integer;
  101.   q, p: TPoint;
  102. begin
  103.   if (High(pts) > -1) then
  104.   begin
  105.     h := High(pts);
  106.     for i := 0 to h do
  107.     begin
  108.       j := (i + 1);
  109.       if (i = h) then
  110.         j := 0;
  111.       q := pts[i];
  112.       p := pts[j];
  113.       r := Length(Result);
  114.       if ((q.X <> p.X) or (q.Y <> p.Y)) then
  115.       begin
  116.         l := Max(Round(Abs(q.X - p.X)), Round(Abs(q.Y - p.Y)));
  117.         SetLength(Result, ((r + l) + 1));
  118.         for a := 0 to l do
  119.           Result[(r + a)] := Point((q.X + Round((p.X - q.X) * (a / Extended(l)))), (q.Y + Round((p.Y - q.Y) * (a / Extended(l)))));
  120.       end else
  121.       begin
  122.         SetLength(Result, (r + 1));
  123.         Result[r] := q;
  124.       end;
  125.     end;
  126.   end else
  127.     SetLength(Result, 0);
  128. end;
  129.  
  130. {==============================================================================]
  131.   Explanation: Check if a point is within a polygon/shape by the given outline points (poly)
  132.                The points MUST be in order, as if you would draw a line trough each point.
  133.   NOTE: Original algorithm by slacky (warpie)
  134. [==============================================================================}
  135. function InPolygon(pt: TPoint; shape: TPointArray): Boolean;
  136. var
  137.   b: TBox;
  138.   x, y, h, i, v, l, r, z: Integer;
  139.   o: TPointArray;
  140.   f: Boolean;
  141.   t: array of TBoolArray;
  142.   e: Extended;
  143.   q, p, d: TPoint;
  144. begin
  145.   h := High(shape);
  146.   Result := False;
  147.   if (h > -1) then
  148.   begin
  149.     b := IntToBox(shape[0].X, shape[0].Y, shape[0].X, shape[0].Y);
  150.     for i := 0 to h do
  151.     begin
  152.       if (shape[i].X < b.X1) then
  153.         b.X1 := shape[i].X
  154.       else
  155.         if (shape[i].X > b.X2) then
  156.           b.X2 := shape[i].X;
  157.       if (shape[i].Y < b.Y1) then
  158.         b.Y1 := shape[i].Y
  159.       else
  160.         if (shape[i].Y > b.Y2) then
  161.           b.Y2 := shape[i].Y;
  162.     end;
  163.     if ((pt.X >= b.X1) and (pt.Y >= b.Y1) and (pt.X <= b.X2) and (pt.Y <= b.Y2)) then
  164.     begin
  165.       SetLength(t, ((b.X2 - b.X1) + 1));
  166.       for i := 0 to (b.X2 - b.X1) do
  167.         SetLength(t[i], ((b.Y2 - b.Y1) + 1));
  168.       for i := 0 to h do
  169.       begin
  170.         v := (i + 1);
  171.         if (i = h) then
  172.           v := 0;
  173.         q := shape[i];
  174.         p := shape[v];
  175.         r := Length(o);
  176.         if ((q.X <> p.X) or (q.Y <> p.Y)) then
  177.         begin
  178.           l := Max(Round(Abs(q.X - p.X)), Round(Abs(q.Y - p.Y)));
  179.           SetLength(o, ((r + l) + 1));
  180.           for z := 0 to l do
  181.             o[(r + z)] := Point((q.X + Round((p.X - q.X) * (z / Extended(l)))), (q.Y + Round((p.Y - q.Y) * (z / Extended(l)))));
  182.         end else
  183.         begin
  184.           SetLength(o, (r + 1));
  185.           o[r] := q;
  186.         end;
  187.       end;
  188.       l := Length(o);
  189.       for i := 0 to (l - 1) do
  190.         if not t[(o[i].X - b.X1)][(o[i].Y - b.Y1)] then
  191.            t[(o[i].X - b.X1)][(o[i].Y - b.Y1)] := True;
  192.       for y := 0 to (b.Y2 - b.Y1) do
  193.       begin
  194.         for x := 0 to (b.X2 - b.X1) do
  195.         begin
  196.           f := t[x][y];
  197.           if not f then
  198.           begin
  199.             d := Point((x + b.X1), (y + b.Y1));
  200.             q := shape[0];
  201.             for i := 0 to (h + 1) do
  202.             begin
  203.               p := shape[(i mod (h + 1))];
  204.               if (d.Y > Min(q.Y, p.Y)) then
  205.                 if (d.Y <= Max(q.Y, p.Y)) then
  206.                   if (d.X <= Max(q.X, p.X)) then
  207.                   begin
  208.                     if (q.y <> p.y) then
  209.                       e := ((d.Y - q.Y) * (p.X - q.X) / Extended((p.Y - q.Y)) + q.X);
  210.                     if ((q.X = p.X) or (d.X < e)) then
  211.                       f := not f;
  212.                   end;
  213.               q := p;
  214.             end;
  215.           end;
  216.           if f then
  217.           begin
  218.             t[x][y] := True;
  219.             Result := t[(pt.X - b.X1)][(pt.Y - b.Y1)];
  220.           end;
  221.         end;
  222.         if Result then
  223.           Break;
  224.       end;
  225.       SetLength(t, 0);
  226.     end;
  227.   end;
  228. end;
  229.  
  230. { Creates all the points needed to define a simple polygon }
  231. function TPAXagon(sides: Integer; C, S: TPoint): TPointArray;
  232. var
  233.   x, y, a, b, v: Integer;
  234.   n, m: Extended;
  235. begin
  236.   SetLength(Result, sides);
  237.   x := S.x;
  238.   y := S.y;
  239.   n := Sin(Radians(360.0 / sides));
  240.   m := Cos(Radians(360.0 / sides));
  241.   for v := 0 to (sides - 1) do
  242.   begin
  243.     a := (x - C.x);
  244.     b := (y - C.y);
  245.     x := Round(((b * n) + (a * m) + C.x));
  246.     y := Round(((b * m) - (a * n) + C.y));
  247.     Result[v] := Point(x, y);
  248.   end;
  249. end;
  250.  
  251. //******* DIRTY EXAMPLE BELLOW: *******//
  252. procedure SetPixels(bmp: Integer; TPA: TPointArray; color: Integer);
  253. var
  254.   a, z, w, h: Integer;
  255. begin
  256.   z := High(TPA);
  257.   if (z > -1) then
  258.   begin
  259.     GetBitmapSize(bmp, w, h);
  260.     for a := 0 to z do
  261.       if ((TPA[a].X >= 0) and (TPA[a].Y >= 0) and (TPA[a].X < w) and (TPA[a].Y < h)) then
  262.         FastSetPixel(bmp, TPA[a].X, TPA[a].Y, color);
  263.   end;
  264. end;
  265.  
  266. procedure SetPixelsMP(bmp: Integer; TPA: TPointArray; color: Integer);
  267. var
  268.   a, z, w, h: Integer;
  269. begin
  270.   z := High(TPA);
  271.   if (z > -1) then
  272.   begin
  273.     GetBitmapSize(bmp, w, h);
  274.     for a := 0 to z do
  275.       if ((TPA[a].X > 0) and (TPA[a].Y > 0) and (TPA[a].X < (w - 1)) and (TPA[a].Y < (h - 1))) then
  276.       begin
  277.         FastSetPixel(bmp, (TPA[a].X - 1), TPA[a].Y, color);
  278.         FastSetPixel(bmp, (TPA[a].X + 1), TPA[a].Y, color);
  279.         FastSetPixel(bmp, TPA[a].X, (TPA[a].Y + 1), color);
  280.         FastSetPixel(bmp, TPA[a].X, (TPA[a].Y - 1), color);
  281.       end;
  282.   end;
  283. end;
  284.  
  285. //******* Plot a few shapes using this algorithm *******//
  286. var
  287.   shape, TPA: TPointArray;
  288.   bmp, t: Integer;
  289.   ShowExample: Integer;
  290.   ShowPoints: Boolean;
  291.  
  292. begin
  293.   //Dynamic shapes from Example 6 and down:
  294.   ShowExample := 4; //0 - 9
  295.   ShowPoints := True;  //0 or 1
  296.   case ShowExample of
  297.     // Microshape ------//
  298.     //           TOP            LEFT           BOTTOM         RIGHT
  299.     0: shape := [Point(50, 50), Point(50, 51), Point(51, 50), Point(51, 51)];
  300.     // Arrow like shape //
  301.     1: shape := [Point(70,90),Point(185,90),Point(185,116), Point(70,116), //Square +
  302.                  Point(70,140),Point(35,105),Point(70,70)];                //Triangle
  303.     // Triangle --------//
  304.     2: shape := [Point(50,50),Point(0,100),Point(100,150)];
  305.     // Raped pentagon --//
  306.     3: shape := [Point(10,25),Point(35,5),Point(82,22),Point(50,90),Point(4,60)];
  307.     // Octagon ---------//
  308.     4: shape := [Point(100,30), Point(155,50),  //Top-Right
  309.                  Point(180,110),Point(155,160), //Right-Bottom
  310.                  Point(100,180),Point(45,160),  //Bottom-Left
  311.                  Point(20,100), Point(45,50)];  //Left-Top
  312.     // S-shape ---------//
  313.     5: shape := [Point(135,50),Point(123,70),Point(103,58),Point(85,70),Point(85,85),
  314.                  Point(122,105),Point(132,125),Point(120,155),Point(78,164),Point(55,147),
  315.                  Point(64,128),Point(80,140),Point(100,140),Point(96,116),Point(62,98),
  316.                  Point(60,55),Point(111,35)];
  317.     // Xagon: 15 corners //
  318.     6: shape := TPAXagon(15, Point(100,100), Point(60,100));
  319.     // Xagon: 9 corners //
  320.     7: shape := TPAXagon(9, Point(100,100), Point(60,50));
  321.     // Xagon: 5 corners AKA Pentagon //
  322.     8: shape := TPAXagon(5, Point(100,100), Point(74,50));
  323.     // Xagon: 3 corners AKA Triangle //
  324.     9: shape := TPAXagon(3, Point(100,100), Point(48,48));
  325.   end;
  326.   bmp := CreateBitmap(200, 200);
  327.   t := GetSystemTime;
  328.   TPA := TPAPolygon(shape);
  329.   WriteLn(IntToStr(GetSystemTime - t) + ' ms.');
  330.   SetPixels(bmp, TPA, 357435);
  331.   if ShowPoints then
  332.     SetPixelsMP(bmp, shape, 16777215);
  333.   DisplayDebugImgWindow(200, 200);
  334.   DrawBitmapDebugImg(bmp);
  335.   FreeBitmap(bmp);
  336.   SetLength(TPA, 0);
  337. end.
Advertisement
Add Comment
Please, Sign In to add comment