Janilabo

TPA Polygon Development

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