home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 November / CDVD1105.ISO / Software / Freeware / programare / graphics32 / Examples / Clx / Transform_Ex / MainUnit.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2004-07-14  |  15.7 KB  |  602 lines

  1. unit MainUnit;
  2.  
  3. (* ***** BEGIN LICENSE BLOCK *****
  4.  * Version: MPL 1.1
  5.  *
  6.  * The contents of this file are subject to the Mozilla Public License Version
  7.  * 1.1 (the "License"); you may not use this file except in compliance with
  8.  * the License. You may obtain a copy of the License at
  9.  * http://www.mozilla.org/MPL/
  10.  *
  11.  * Software distributed under the License is distributed on an "AS IS" basis,
  12.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  13.  * for the specific language governing rights and limitations under the
  14.  * License.
  15.  *
  16.  * The Original Code is Graphics32
  17.  *
  18.  * The Initial Developer of the Original Code is
  19.  * Alex A. Denisov
  20.  *
  21.  * Portions created by the Initial Developer are Copyright (C) 2000-2004
  22.  * the Initial Developer. All Rights Reserved.
  23.  *
  24.  * Contributor(s):
  25.  *
  26.  * ***** END LICENSE BLOCK ***** *)
  27.  
  28. interface
  29.  
  30. uses
  31.   SysUtils, Classes, QGraphics, QControls, QForms, QDialogs,
  32.   GR32, GR32_Image, GR32_Transforms, GR32_Layers, QExtCtrls, QStdCtrls, QButtons,
  33.   QComCtrls, QGrids, GR32_RangeBars;
  34.  
  35. type
  36.   TOpType = (opNone, opTranslate, opScale, opRotate, opSkew);
  37.   TOpRec = record
  38.     OpType: TOpType;
  39.     Dx, Dy: Extended;        // shifts for opTranslate mode
  40.     Sx, Sy: Extended;        // scale factors for opScale mode
  41.     Cx, Cy, Alpha: Extended; // rotation center and angle (deg) for opRotate mode
  42.     Fx, Fy: Extended;        // skew factors for opSkew mode
  43.   end;
  44.   TOpRecs = array[0..7] of TOpRec;
  45.  
  46. const
  47.   OpTypes: array [0..4] of TOpType = (opNone, opTranslate, opScale, opRotate,
  48.     opSkew);
  49.  
  50. type
  51.   TTransformMode = (tmAffine, tmProjective, tmBilinear);
  52.  
  53.   TForm1 = class(TForm)
  54.     Src: TImage32;
  55.     Dst: TImage32;
  56.     PageControl1: TPageControl;
  57.     TabSheet1: TTabSheet;
  58.     Panel2: TPanel;
  59.     Shape1: TShape;
  60.     Shape2: TShape;
  61.     StringGrid: TStringGrid;
  62.     ListBox: TListBox;
  63.     Button1: TButton;
  64.     Label9: TLabel;
  65.     CodeString: TEdit;
  66.     Panel1: TPanel;
  67.     Label1: TLabel;
  68.     ComboBox: TComboBox;
  69.     Label10: TLabel;
  70.     RadioGroup1: TRadioGroup;
  71.     Panel3: TPanel;
  72.     TabSheet2: TTabSheet;
  73.     Label18: TLabel;
  74.     OpacityBar: TGaugeBar;
  75.     PageControl: TPageControl;
  76.     tabDummy: TTabSheet;
  77.     tabTranslate: TTabSheet;
  78.     tabSkew: TTabSheet;
  79.     tabRotate: TTabSheet;
  80.     tabScale: TTabSheet;
  81.     Label2: TLabel;
  82.     Label3: TLabel;
  83.     Label4: TLabel;
  84.     Label5: TLabel;
  85.     eDx: TEdit;
  86.     eDy: TEdit;
  87.     sbDx: TGaugeBar;
  88.     sbDy: TGaugeBar;
  89.     Label11: TLabel;
  90.     Label13: TLabel;
  91.     Label16: TLabel;
  92.     Label15: TLabel;
  93.     eCx: TEdit;
  94.     eAlpha: TEdit;
  95.     eCy: TEdit;
  96.     sbAlpha: TGaugeBar;
  97.     Label6: TLabel;
  98.     Label7: TLabel;
  99.     Label8: TLabel;
  100.     eSy: TEdit;
  101.     eSx: TEdit;
  102.     sbSx: TGaugeBar;
  103.     sbSy: TGaugeBar;
  104.     Label12: TLabel;
  105.     Label14: TLabel;
  106.     Label17: TLabel;
  107.     eFx: TEdit;
  108.     eFy: TEdit;
  109.     sbFx: TGaugeBar;
  110.     sbFy: TGaugeBar;
  111.     procedure FormCreate(Sender: TObject);
  112.     procedure FormDestroy(Sender: TObject);
  113.     procedure ListBoxClick(Sender: TObject);
  114.     procedure ComboBoxChange(Sender: TObject);
  115.     procedure TranslationChanged(Sender: TObject);
  116.     procedure ScaleChanged(Sender: TObject);
  117.     procedure TranslationScrolled(Sender: TObject);
  118.     procedure Button1Click(Sender: TObject);
  119.     procedure ScaleScrolled(Sender: TObject);
  120.     procedure RotationChanged(Sender: TObject);
  121.     procedure RotationScrolled(Sender: TObject);
  122.     procedure SkewChanged(Sender: TObject);
  123.     procedure SkewScrolled(Sender: TObject);
  124.     procedure RadioGroup1Click(Sender: TObject);
  125.     procedure OpacityChange(Sender: TObject);
  126.     procedure PageControl1Change(Sender: TObject);
  127.  
  128.     procedure RubberLayerMouseDown(Sender: TObject; Button: TMouseButton;
  129.       Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  130.     procedure RubberLayerMouseMove(Sender: TObject; Shift: TShiftState; X,
  131.       Y: Integer; Layer: TCustomLayer);
  132.     procedure RubberLayerMouseUp(Sender: TObject; Button: TMouseButton;
  133.       Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  134.  
  135.     procedure AppEventsIdle(Sender: TObject; var Done: Boolean);
  136.   protected
  137.     LoadingValues: Boolean;
  138.     DraggedVertex: Integer;
  139.     LastMousePos: TPoint;
  140.     StippleStart: Single;
  141.     procedure PaintHandles(Sender: TObject; BackBuffer: TBitmap32);
  142.   public
  143.     Operation: TOpRecs;
  144.     Current: ^TOpRec;
  145.     AT: TAffineTransformation;
  146.     PT: TProjectiveTransformation;
  147.     TT: TTransformation;
  148.     Vertices: array[0..3] of TPoint;
  149.     Mode: TTransformMode;
  150.     procedure ClearTransformations;
  151.     procedure DoTransform;
  152.     procedure GenTransform;
  153.     procedure PrepareSource;
  154.     procedure ShowSettings(OperationNum: Integer);
  155.     procedure InitVertices; // for projective mapping
  156.   end;
  157.  
  158. var
  159.   Form1: TForm1;
  160.  
  161. implementation
  162.  
  163. function GetVal(Src: string; var Dst: Extended): Boolean;
  164. var
  165.   Code: Integer;
  166. begin
  167.   Val(Src, Dst, Code);
  168.   Result := Code = 0;
  169. end;
  170.  
  171. {$R *.xfm}
  172.  
  173. procedure TForm1.FormCreate(Sender: TObject);
  174. begin
  175.   with TCustomLayer.Create(Dst.Layers) do
  176.   begin
  177.     OnPaint := PaintHandles;
  178.   end;
  179.  
  180.   DraggedVertex := -1;
  181.   Dst.SetupBitmap; // set the destination bitmap size to match the image size
  182.   PrepareSource;
  183.   ClearTransformations;
  184.   ShowSettings(0);
  185.   AT := TAffineTransformation.Create;
  186.   PT := TProjectiveTransformation.Create;
  187.   TT := AT;
  188.   DoTransform;
  189.  
  190.   Application.OnIdle := AppEventsIdle;
  191.   StringGrid.Col := 0;
  192.   StringGrid.Row := 0;
  193. end;
  194.  
  195. procedure TForm1.ClearTransformations;
  196. var
  197.   I: Integer;
  198. begin
  199.   FillChar(Operation[0], SizeOf(TOpRecs), 0);
  200.   for I := 0 to 7 do
  201.   begin
  202.     Operation[I].Sx := 1;
  203.     Operation[I].Sy := 1;
  204.     Operation[I].Cx := Src.Bitmap.Width / 2;
  205.     Operation[I].Cy := Src.Bitmap.Height / 2;
  206.   end;
  207. end;
  208.  
  209. procedure TForm1.PrepareSource;
  210. begin
  211.   // make the border pixels transparent while keeping their RGB components
  212.   SetBorderTransparent(Src.Bitmap,
  213.     Rect(0, 0, Src.Bitmap.Width - 1, Src.Bitmap.Height - 1));
  214. end;
  215.  
  216. procedure TForm1.DoTransform;
  217. var
  218.   i, j: Integer;
  219.   P: PColor32;
  220. begin
  221.   Application.ProcessMessages;
  222.   GenTransform;
  223.   Dst.BeginUpdate;
  224.  
  225.   // Fill Dst with checkerboard pattern
  226.   P := Dst.Bitmap.PixelPtr[0, 0];
  227.   for j := 0 to Dst.Bitmap.Height - 1 do
  228.     for i := 0 to Dst.Bitmap.Width - 1 do
  229.     begin
  230.       if Odd(i shr 4) = Odd(j shr 4) then P^ := clGray32
  231.       else P^ := clWhite32;
  232.       Inc(P);
  233.     end;
  234.  
  235.   Transform(Dst.Bitmap, Src.Bitmap, TT);
  236.   Dst.EndUpdate;
  237.   Dst.Repaint;
  238.  
  239.   if Mode = tmAffine then
  240.   begin
  241.     // fill the string grid
  242.     for j := 0 to 2 do
  243.       for i := 0 to 2 do
  244.         StringGrid.Cells[i, j] := Format('%.3g', [AT.Matrix[i, j]]);
  245.     StringGrid.Col := 3; // hide grid cursor
  246.   end;
  247. end;
  248.  
  249. procedure TForm1.GenTransform;
  250. var
  251.   I: Integer;
  252.   Rec: TOpRec;
  253.   S: string;
  254. begin
  255.   TT.SrcRect := FloatRect(0, 0, Src.Bitmap.Width - 1, Src.Bitmap.Height - 1);
  256.   if Mode = tmProjective then
  257.   begin
  258.     PT.X0 := Vertices[0].X;
  259.     PT.Y0 := Vertices[0].Y;
  260.     PT.X1 := Vertices[1].X;
  261.     PT.Y1 := Vertices[1].Y;
  262.     PT.X2 := Vertices[2].X;
  263.     PT.Y2 := Vertices[2].Y;
  264.     PT.X3 := Vertices[3].X;
  265.     PT.Y3 := Vertices[3].Y;
  266.   end
  267.   else {if Mode = tmAffine then }
  268.   begin
  269.     // affine mode
  270.     AT.Clear;
  271.     for I := 0 to 7 do
  272.     begin
  273.       Rec := Operation[I];
  274.       case Rec.OpType of
  275.         opTranslate:  AT.Translate(Rec.Dx, Rec.Dy);
  276.         opScale:      AT.Scale(Rec.Sx, Rec.Sy);
  277.         opRotate:     AT.Rotate(Rec.Cx, Rec.Cy, Rec.Alpha);
  278.         opSkew:       AT.Skew(Rec.Fx, Rec.Fy);
  279.       end;
  280.       case Rec.OpType of
  281.         opTranslate:  s := s + Format('Translate(%.3g, %.3g); ', [Rec.Dx, Rec.Dy]);
  282.         opScale:      s := s + Format('Scale(%.3g, %.3g); ', [Rec.Sx, Rec.Sy]);
  283.         opRotate:     s := s + Format('Rotate(%.3g, %.3g, %3g); ', [Rec.Cx, Rec.Cy, Rec.Alpha]);
  284.         opSkew:       s := s + Format('Skew(%.3g, %.3g); ', [Rec.Fx, Rec.Fy]);
  285.       end;
  286.     end;
  287.     if Length(s) = 0 then s := 'Clear;';
  288.     CodeString.Text := s;
  289.   end;
  290. end;
  291.  
  292. procedure TForm1.FormDestroy(Sender: TObject);
  293. begin
  294.   AT.Free;
  295.   PT.Free;
  296. end;
  297.  
  298. procedure TForm1.Button1Click(Sender: TObject);
  299. begin
  300.   ClearTransformations;
  301.   ShowSettings(Listbox.ItemIndex);
  302.   DoTransform;
  303. end;
  304.  
  305. procedure TForm1.ListBoxClick(Sender: TObject);
  306. begin
  307.   ShowSettings(ListBox.ItemIndex);
  308. end;
  309.  
  310. procedure TForm1.ShowSettings(OperationNum: Integer);
  311. begin
  312.   LoadingValues := True;
  313.   ListBox.ItemIndex := OperationNum;
  314.   Current := @Operation[OperationNum];
  315.   Combobox.ItemIndex := Ord(Current.OpType);
  316.   PageControl.ActivePageIndex := Ord(Current.OpType);
  317.   eDx.Text := Format('%.4g', [Current.Dx]);
  318.   eDy.Text := Format('%.4g', [Current.Dy]);
  319.   sbDx.Position := Round(Current.Dx * 10);
  320.   sbDy.Position := Round(Current.Dy * 10);
  321.   eSx.Text := Format('%.4g', [Current.Sx]);
  322.   eSy.Text := Format('%.4g', [Current.Sy]);
  323.   sbSx.Position := Round(Current.Sx * 100);
  324.   sbSy.Position := Round(Current.Sy * 100);
  325.   eCx.Text := Format('%.4g', [Current.Cx]);
  326.   eCy.Text := Format('%.4g', [Current.Cy]);
  327.   eAlpha.Text := Format('%.4g', [Current.Alpha]);
  328.   sbAlpha.Position := Round(Current.Alpha * 2);
  329.   eFx.Text := Format('%.4g', [Current.Fx]);
  330.   eFy.Text := Format('%.4g', [Current.Fy]);
  331.   sbFx.Position := Round(Current.Fx * 100);
  332.   sbFy.Position := Round(Current.Fy * 100);
  333.   LoadingValues := False;
  334. end;
  335.  
  336. procedure TForm1.ComboBoxChange(Sender: TObject);
  337. begin
  338.   Current.OpType := OpTypes[ComboBox.ItemIndex];
  339.   ShowSettings(ListBox.ItemIndex);
  340.   DoTransform;
  341. end;
  342.  
  343. procedure TForm1.TranslationChanged(Sender: TObject);
  344. var
  345.   Tx, Ty: Extended;
  346. begin
  347.   if LoadingValues then Exit;
  348.   if GetVal(eDx.Text, Tx) and GetVal(eDy.Text, Ty) then
  349.   begin
  350.     Current.Dx := Tx;
  351.     Current.Dy := Ty;
  352.     DoTransform;
  353.     LoadingValues := True;
  354.     sbDx.Position := Round(Current.Dx * 10);
  355.     sbDy.Position := Round(Current.Dy * 10);
  356.     LoadingValues := False;
  357.   end;
  358. end;
  359.  
  360. procedure TForm1.TranslationScrolled(Sender: TObject);
  361. begin
  362.   if LoadingValues then Exit;
  363.   Current.Dx := sbDx.Position / 10;
  364.   Current.Dy := sbDy.Position / 10;
  365.   DoTransform;
  366.   LoadingValues := True;
  367.   eDx.Text := FloatToStr(Current.Dx);
  368.   eDy.Text := FloatToStr(Current.Dy);
  369.   LoadingValues := False;
  370. end;
  371.  
  372. procedure TForm1.ScaleChanged(Sender: TObject);
  373. var
  374.   Sx, Sy: Extended;
  375. begin
  376.   if LoadingValues then Exit;
  377.   if GetVal(eSx.Text, Sx) and GetVal(eSy.Text, Sy) then
  378.   begin
  379.     Current.Sx := Sx;
  380.     Current.Sy := Sy;
  381.     DoTransform;
  382.     LoadingValues := True;
  383.     sbSx.Position := Round(Current.Sx * 100);
  384.     sbSy.Position := Round(Current.Sy * 100);
  385.     LoadingValues := False;
  386.   end;
  387. end;
  388.  
  389. procedure TForm1.ScaleScrolled(Sender: TObject);
  390. begin
  391.   if LoadingValues then Exit;
  392.   Current.Sx := sbSx.Position / 100;
  393.   Current.Sy := sbSy.Position / 100;
  394.   DoTransform;
  395.   LoadingValues := True;
  396.   eSx.Text := FloatToStr(Current.Sx);
  397.   eSy.Text := FloatToStr(Current.Sy);
  398.   LoadingValues := False;
  399. end;
  400.  
  401. procedure TForm1.RotationChanged(Sender: TObject);
  402. var
  403.   Cx, Cy, Alpha: Extended;
  404. begin
  405.   if LoadingValues then Exit;
  406.   if GetVal(eCx.Text, Cx) and GetVal(eCy.Text, Cy) and
  407.     GetVal(eAlpha.Text, Alpha) then
  408.   begin
  409.     Current.Cx := Cx;
  410.     Current.Cy := Cy;
  411.     Current.Alpha := Alpha;
  412.     DoTransform;
  413.     LoadingValues := True;
  414.     sbAlpha.Position := Round(Alpha * 2);
  415.     LoadingValues := False;
  416.   end;
  417. end;
  418.  
  419. procedure TForm1.RotationScrolled(Sender: TObject);
  420. begin
  421.   if LoadingValues then Exit;
  422.   Current.Alpha := sbAlpha.Position / 2;
  423.   DoTransform;
  424.   LoadingValues := True;
  425.   eAlpha.Text := FloatToStr(Current.Alpha / 2);
  426.   LoadingValues := False;
  427. end;
  428.  
  429. procedure TForm1.SkewChanged(Sender: TObject);
  430. var
  431.   Fx, Fy: Extended;
  432. begin
  433.   if LoadingValues then Exit;
  434.   if GetVal(eFx.Text, Fx) and GetVal(eFy.Text, Fy) then
  435.   begin
  436.     Current.Fx := Fx;
  437.     Current.Fy := Fy;
  438.     DoTransform;
  439.     LoadingValues := True;
  440.     sbFx.Position := Round(Current.Fx * 10);
  441.     sbFy.Position := Round(Current.Fy * 10);
  442.     LoadingValues := False;
  443.   end;
  444. end;
  445.  
  446. procedure TForm1.SkewScrolled(Sender: TObject);
  447. begin
  448.   if LoadingValues then Exit;
  449.   Current.Fx := sbFx.Position / 10;
  450.   Current.Fy := sbFy.Position / 10;
  451.   DoTransform;
  452.   LoadingValues := True;
  453.   eFx.Text := FloatToStr(Current.Fx);
  454.   eFy.Text := FloatToStr(Current.Fy);
  455.   LoadingValues := False;
  456. end;
  457.  
  458. procedure TForm1.RadioGroup1Click(Sender: TObject);
  459. const
  460.   STRETCH_FILTER: array [0..1] of TStretchFilter = (sfNearest, sfLinear);
  461. begin
  462.   Src.Bitmap.StretchFilter := STRETCH_FILTER[RadioGroup1.ItemIndex];
  463.   DoTransform;
  464. end;
  465.  
  466. procedure TForm1.OpacityChange(Sender: TObject);
  467. begin
  468.   OpacityBar.Update;
  469.   Src.Bitmap.MasterAlpha := OpacityBar.Position;
  470.   DoTransform;
  471. end;
  472.  
  473. procedure TForm1.InitVertices;
  474. begin
  475.   Vertices[0].X := 0;
  476.   Vertices[0].Y := 0;
  477.   Vertices[1].X := Src.Bitmap.Width - 1;
  478.   Vertices[1].Y := 0;
  479.   Vertices[2].X := Src.Bitmap.Width - 1;
  480.   Vertices[2].Y := Src.Bitmap.Height - 1;
  481.   Vertices[3].X := 0;
  482.   Vertices[3].Y := Src.Bitmap.Height - 1;
  483. end;
  484.  
  485. procedure TForm1.PageControl1Change(Sender: TObject);
  486. begin
  487.   if PageControl1.ActivePage = TabSheet1 then
  488.   begin
  489.     Mode := tmAffine;
  490.     TT := AT;
  491.     RadioGroup1.Parent := TabSheet1;
  492.   end
  493.   else {if PageControl1.ActivePage = TabSheet2 then }
  494.   begin
  495.     // set current transformation as projective
  496.     Mode := tmProjective;
  497.     TT := PT;
  498.     InitVertices;
  499.     RadioGroup1.Parent := TabSheet2;
  500.   end;
  501.   DoTransform;
  502. end;
  503.  
  504. procedure TForm1.RubberLayerMouseDown(Sender: TObject;
  505.   Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  506. var
  507.   I: Integer;
  508. begin
  509.   if Mode = tmAffine then Exit;
  510.  
  511.   DraggedVertex := -1;
  512.  
  513.   // find the vertex to drag
  514.   for I := 0 to 3 do
  515.     if (Abs(Vertices[I].X - X) < 3) and (Abs(Vertices[I].Y - Y) < 3) then
  516.     begin
  517.       DraggedVertex := I;
  518.       Break;
  519.     end;
  520.  
  521.   // or drag all of them, (DragVertex = 4)
  522.   if DraggedVertex = -1 then DraggedVertex := 4;
  523.  
  524.   // store current mouse position
  525.   LastMousePos := Point(X, Y);
  526. end;
  527.  
  528. procedure TForm1.RubberLayerMouseMove(Sender: TObject; Shift: TShiftState;
  529.   X, Y: Integer; Layer: TCustomLayer);
  530. var
  531.   Dx, Dy, I: Integer;
  532. begin
  533.   if Mode = tmAffine then Exit;
  534.   
  535.   if DraggedVertex = -1 then Exit; // mouse is not pressed
  536.  
  537.   Dx := X - LastMousePos.X;
  538.   Dy := Y - LastMousePos.Y;
  539.   LastMousePos := Point(X, Y);
  540.  
  541.   // update coords
  542.   if DraggedVertex = 4 then
  543.   begin
  544.     for I := 0 to 3 do
  545.     begin
  546.       Inc(Vertices[I].X, Dx);
  547.       Inc(Vertices[I].Y, Dy);
  548.     end;
  549.   end
  550.   else
  551.   begin
  552.     Inc(Vertices[DraggedVertex].X, Dx);
  553.     Inc(Vertices[DraggedVertex].Y, Dy);
  554.   end;
  555.  
  556.   DoTransform;
  557. end;
  558.  
  559. procedure TForm1.RubberLayerMouseUp(Sender: TObject; Button: TMouseButton;
  560.   Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  561. begin
  562.   DraggedVertex := -1;
  563. end;
  564.  
  565. procedure TForm1.AppEventsIdle(Sender: TObject; var Done: Boolean);
  566. begin
  567.   StippleStart := StippleStart - 0.05;
  568.   Dst.Invalidate;
  569. end;
  570.  
  571. procedure TForm1.PaintHandles(Sender: TObject; BackBuffer: TBitmap32);
  572. var
  573.   I, X0, Y0, X1, Y1: Integer;
  574.  
  575.   procedure PaintVertex(X, Y: Integer);
  576.   begin
  577.     BackBuffer.FillRectS(X - 2, Y - 2, X + 2, Y + 2, clWhite32);
  578.     BackBuffer.FrameRectS(X - 3, Y - 3, X + 3, Y + 3, clBlack32);
  579.   end;
  580.  
  581. begin
  582.   if PageControl1.ActivePage = TabSheet1 then Exit;
  583.  
  584.   BackBuffer.SetStipple([clBlack32, clBlack32, clWhite32, clWhite32]);
  585.   BackBuffer.StippleStep := 0.5;
  586.   BackBuffer.StippleCounter := StippleStart;
  587.  
  588.   X0 := Vertices[3].X;
  589.   Y0 := Vertices[3].Y;
  590.   for I := 0 to 3 do
  591.   begin
  592.     X1 := Vertices[I].X;
  593.     Y1 := Vertices[I].Y;
  594.     BackBuffer.LineFSP(X0, Y0, X1, Y1);
  595.     X0 := X1;
  596.     Y0 := Y1;
  597.   end;
  598.   for I := 0 to 3 do PaintVertex(Vertices[I].X, Vertices[I].Y);
  599. end;
  600.  
  601. end.
  602.