123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- unit fCurves;
- (* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1 or LGPL 2.1 with linking exception
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * Alternatively, the contents of this file may be used under the terms of the
- * Free Pascal modified version of the GNU Lesser General Public License
- * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
- * of this license are applicable instead of those above.
- * Please see the file LICENSE.txt for additional information concerning this
- * license.
- *
- * The Original Code is Curves Example (based on VPR example)
- *
- * The Initial Developer of the Original Code is
- * Mattias Andersson <[email protected]>
- *
- * Portions created by the Initial Developer are Copyright (C) 2000-2005
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Christian-W. Budde (GR32 version 2.0 port)
- *
- * ***** END LICENSE BLOCK ***** *)
- interface
- {$I GR32.inc}
- uses
- {$IFDEF FPC} LCLIntf, LResources, Buttons, {$ENDIF}
- Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls,
- ExtCtrls, GR32_Image;
- type
- TMainForm = class(TForm)
- BtnDrawCurve: TButton;
- CbxUpdate: TCheckBox;
- Img: TImage32;
- procedure BtnDrawCurveClick(Sender: TObject);
- procedure CbxUpdateClick(Sender: TObject);
- procedure ApplicationIdleHandler(Sender: TObject; var Done: Boolean);
- private
- end;
- var
- MainForm: TMainForm;
- implementation
- {$IFDEF FPC}
- {$R *.lfm}
- {$ELSE}
- {$R *.dfm}
- {$ENDIF}
- uses
- Math, GR32, GR32_Geometry, GR32_VectorUtils, GR32_Resamplers, GR32_LowLevel,
- GR32_Polygons;
- function MakeCurve(const Points: TArrayOfFloatPoint; Kernel: TCustomKernel;
- Closed: Boolean): TArrayOfFloatPoint;
- const
- TOLERANCE: TFloat = 20.0;
- THRESHOLD: TFloat = 0.5;
- var
- I, H, R: Integer;
- Filter: TFilterMethod;
- WrapProc: TWrapProc;
- procedure AddPoint(const P: TFloatPoint);
- var
- L: Integer;
- begin
- L := Length(Result);
- SetLength(Result, L + 1);
- Result[L] := P;
- end;
- function GetPoint(I: Integer; t: TFloat = 0.0): TFloatPoint;
- var
- f, Index: Integer;
- W: TFloat;
- begin
- Result.X := 0; Result.Y := 0;
- for f := -R to R do
- begin
- Index := WrapProc(I - f, H);
- W := Filter(f + t);
- Result.X := Result.X + W * Points[Index].X;
- Result.Y := Result.Y + W * Points[Index].Y;
- end;
- end;
- procedure Recurse(I: Integer; const P1, P2: TFloatPoint; const t1, t2: TFloat);
- var
- Temp: TFloat;
- P: TFloatPoint;
- begin
- AddPoint(P1);
- Temp := (t1 + t2) * 0.5;
- P := GetPoint(I, Temp);
- if (Abs(CrossProduct(FloatPoint(P1.X - P.X, P1.Y - P.Y),
- FloatPoint(P.X - P2.X, P.Y - P2.Y))) > TOLERANCE) or (t2 - t1 >= THRESHOLD) then
- begin
- Recurse(I, P1, P, t1, Temp);
- Recurse(I, P, P2, Temp, t2);
- end
- else AddPoint(P);
- end;
- const
- WRAP_PROC: array[Boolean] of TWrapProc = (Clamp, Wrap);
- begin
- WrapProc := Wrap_PROC[Closed];
- Filter := Kernel.Filter;
- R := Ceil(Kernel.GetWidth);
- H := High(Points);
- for I := 0 to H - 1 do
- Recurse(I, GetPoint(I), GetPoint(I + 1), 0, 1);
- if Closed then
- Recurse(H, GetPoint(H), GetPoint(0), 0, 1)
- else
- AddPoint(GetPoint(H));
- end;
- procedure TMainForm.BtnDrawCurveClick(Sender: TObject);
- var
- PX, PY: TArrayOfFloatPoint;
- I: Integer;
- K: TCustomKernel;
- X, Y: Integer;
- begin
- //Randomize;
- Img.SetupBitmap(True, $FF333333);
- SetLength(PX, 8);
- // create a set of random data points
- for I := 0 to High(PX) do
- PX[I] := FloatPoint(Random(Img.Width), Random(Img.Height));
- // create interpolation kernel
- K := TGaussianKernel.Create;
- try
- // subdivide recursively and interpolate
- PY := MakeCurve(PX, K, True);
- finally
- K.Free;
- end;
- // draw result polygon
- PolygonFS(Img.Bitmap, PY, $FFCC3300, pfWinding);
- // draw data points
- for I := 0 to High(PY) do
- begin
- X := Floor(PY[I].X);
- Y := Floor(PY[I].Y);
- Img.Bitmap.FillRects(X, Y, X + 1, Y + 1, $FF00FF00);
- end;
- for I := 0 to High(PX) do
- begin
- PY := Circle(PX[I].X, PX[I].Y, 4);
- PolygonFS(Img.Bitmap, PY, $FF000000);
- PY := Ellipse(PX[I].X, PX[I].Y, 2.75, 2.75);
- PolygonFS(Img.Bitmap, PY, $FF00FF00);
- end;
- end;
- procedure TMainForm.ApplicationIdleHandler(Sender: TObject; var Done: Boolean);
- begin
- BtnDrawCurveClick(Sender);
- end;
- procedure TMainForm.CbxUpdateClick(Sender: TObject);
- begin
- if CbxUpdate.Checked then
- Application.OnIdle := ApplicationIdleHandler
- else
- Application.OnIdle := nil;
- end;
- end.
|