1 unit vtprimitives;
2 
3 {$mode objfpc}{$H+}
4 
5 interface
6 
7 uses
8   Classes, SysUtils, fpcanvas, fpimage, fpvectorial;
9 
CreateCirclenull10 function CreateCircle(APage: TvVectorialPage; CtrX, CtrY, R: Double): TvCircle;
CreateEllipsenull11 function CreateEllipse(APage: TvVectorialPage; X1, Y1, X2, Y2: Double): TvEllipse;
CreateRectanglenull12 function CreateRectangle(APage: TvVectorialPage; X1, Y1, X2, Y2: Double): TvRectangle;
CreateRoundedRectnull13 function CreateRoundedRect(APage: TvVectorialPage; X1, Y1, X2, Y2, RX, RY: Double): TvRectangle;
CreatePolygonnull14 function CreatePolygon(APage: TvVectorialPage; const APoints: array of T3DPoint): TvPolygon;
CreateArcnull15 function CreateArc(APage: TvVectorialPage; X1,Y1, X2,Y2, CX,CY, RX, RY, Angle: Double;
16   Clockwise: Boolean): TPath;
CreateBeziernull17 function CreateBezier(APage: TvVectorialPage; X1,Y1, X2,Y2, X3,Y3, X4,Y4: Double): TPath;
18 
CreateSimpleBrushnull19 function CreateSimpleBrush(AStyle: TFPBrushStyle; AColor: TFPColor): TvBrush; overload;
CreateSimpleBrushnull20 function CreateSimpleBrush(AStyle: TFPBrushStyle): TvBrush; overload;
CreateLinearGradientBrushnull21 function CreateLinearGradientBrush(AStartPt, AEndPt: T2DPoint; AFlags: TvGradientFlags;
22   AStartColor, AEndColor: TFPColor): TvBrush;
CreateRadialGradientBrushnull23 function CreateRadialGradientBrush(CX, CY, R, FX, FY: Double;
24   AStartColor, AEndColor: TFPColor): TvBrush;
CreatePennull25 function CreatePen(AStyle: TFPPenStyle; AWidth: Integer; AColor: TFPColor): TvPen;
26 
CreateStdCirclenull27 function CreateStdCircle(APage: TvVectorialPage): TvCircle;
CreateStdEllipsenull28 function CreateStdEllipse(APage: TvVectorialPage): TvEllipse;
CreateStdRectnull29 function CreateStdRect(APage: TvVectorialPage): TvRectangle;
CreateStdRoundedRectnull30 function CreateStdRoundedRect(APage: TvVectorialPage): TvRectangle;
CreateStdPolygonnull31 function CreateStdPolygon(APage: TvVectorialPage): TvPolygon;
CreateStdSelfIntersectingPolygonnull32 function CreateStdSelfIntersectingPolygon(APage: TvVectorialPage): TvPolygon;
CreatePathWithHolenull33 function CreatePathWithHole(APage: TvVectorialPage): TPath;
34 
StdSolidBrushnull35 function StdSolidBrush: TvBrush;
StdHorizGradientBrushnull36 function StdHorizGradientBrush: TvBrush;
StdVertGradientBrushnull37 function StdVertGradientBrush: TvBrush;
StdLinearGradientBrushnull38 function StdLinearGradientBrush: TvBrush;
StdRadialGradientBrushnull39 function StdRadialGradientBrush: TvBrush;
StdPennull40 function StdPen: TvPen;
41 
42 const
43   PAGE_SIZE = 100;
44 
45 
46 implementation
47 
48 uses
49   Math, fpvutils;
50 
51 { Shapes }
52 
53 { circle with specified center and radius.
54   Valid for any coordinate system }
CreateCirclenull55 function CreateCircle(APage: TvVectorialPage; CtrX, CtrY, R: Double): TvCircle;
56 begin
57   Result := TvCircle.Create(APage);
58   Result.X := CtrX;
59   Result.Y := CtrY;
60   Result.Radius := R;
61   Result.Brush := CreateSimpleBrush(bsClear);
62   Result.Pen := CreatePen(psSolid, 1, colBlack);
63 end;
64 
65 { Ellipse with specified center and halfaxes.
66   Coordinate system uses an upward y axis for input data, but is flipped if needed }
CreateEllipsenull67 function CreateEllipse(APage: TvVectorialPage; X1, Y1, X2, Y2: Double): TvEllipse;
68 begin
69   Result := TvEllipse.Create(APage);
70   Result.X := (X1 + X2) / 2;      // Center
71   Result.Y := (Y1 + Y2) / 2;
72   if APage.UseTopLeftCoordinates then
73     Result.Y := PAGE_SIZE - Result.Y;
74   Result.HorzHalfAxis := abs(X2 - X1) / 2;
75   Result.VertHalfAxis := abs(Y2 - Y1) / 2;
76   Result.Brush := CreateSimpleBrush(bsClear);
77   Result.Pen := CreatePen(psSolid, 1, colBlack);
78 end;
79 
80 { Rectangle with specified top/left corner and width and height.
81   Coordinate system uses an upward y axis for input data, but is flipped if needed. }
CreateRectanglenull82 function CreateRectangle(APage: TvVectorialPage; X1, Y1, X2, Y2: Double): TvRectangle;
83 begin
84   Result := TvRectangle.Create(APage);
85   Result.X := Min(X1, X2);
86   if APage.UseTopLeftCoordinates then
87     Result.Y := Min(PAGE_SIZE-Y1, PAGE_SIZE-Y2) else
88     Result.Y := Max(Y1, Y2);
89   Result.CX := abs(X2 - X1);    // width
90   Result.CY := abs(Y2 - Y1);    // height
91   Result.Brush := CreateSimpleBrush(bsClear);
92   Result.Pen := CreatePen(psSolid, 1, colBlack);
93 end;
94 
95 { Rectangle with rounded corner
96   Coordinate system uses an upward y axis for input data, but is flipped if needed. }
CreateRoundedRectnull97 function CreateRoundedRect(APage: TvVectorialPage;
98   X1, Y1, X2, Y2, RX, RY: Double): TvRectangle;
99 begin
100   Result := TvRectangle.Create(APage);
101   Result.X := Min(X1, X2);
102   if APage.UseTopLeftCoordinates then
103     Result.Y := Min(PAGE_SIZE-Y1, PAGE_SIZE-Y2) else
104     Result.Y := Max(Y1, Y2);
105   Result.CX := abs(X2 - X1);
106   Result.CY := abs(Y2 - Y1);
107   Result.RX := RX;
108   Result.RY := RY;
109   Result.Brush := CreateSimpleBrush(bsClear);
110   Result.Pen := CreatePen(psSolid, 1, colBlack);
111 end;
112 
113 { Polygon with vertices specified in the array.
114   Valid for any coordinate system. }
CreatePolygonnull115 function CreatePolygon(APage: TvVectorialPage;
116   const APoints: Array of T3DPoint): TvPolygon;
117 var
118   i: Integer;
119 begin
120   Result := TvPolygon.Create(APage);
121   SetLength(Result.Points, Length(APoints));
122   for i:=0 to High(APoints) do
123     Result.Points[i] := APoints[i];
124   Result.X := Result.Points[0].X;
125   Result.Y := Result.Points[0].Y;
126   Result.Brush := CreateSimpleBrush(bsClear);
127   Result.Pen := CreatePen(psSolid, 1, colBlack);
128 end;
129 
CreateArcnull130 function CreateArc(APage: TvVectorialPage; X1,Y1, X2,Y2, CX,CY, RX, RY, Angle: Double;
131   Clockwise: Boolean): TPath;
132 var
133   txt: TvText;
134 begin
135   if APage.UseTopLeftCoordinates then begin
136     Y1 := PAGE_SIZE - Y1;
137     Y2 := PAGE_SIZE - Y2;
138     CY := PAGE_SIZE - CY;
139     Angle := -Angle;
140   end;
141   // Don't invert "Clockwise" here. It does not matter where the y axis points to.
142 
143   APage.StartPath(X1, Y1);
144   APage.AddEllipticalArcWithCenterToPath(RX, RY, Angle, X2, Y2, CX, CY, Clockwise);
145   Result := APage.EndPath;
146   Result.Pen := StdPen;
147 
148   txt := TvText.Create(APage);
149   txt.Value.Add('1');
150   txt.X := X1;
151   txt.Y := Y1;
152   txt.Font.Color := colRed;
153   APage.AddEntity(txt);
154 
155   txt := TvText.Create(APage);
156   txt.Value.Add('2');
157   txt.X := X2;
158   txt.Y := Y2;
159   txt.Font.Color := colRed;
160   APage.AddEntity(txt);
161 end;
162 
163 function CreateBezier(APage: TvVectorialPage;
164   X1,Y1, X2,Y2, X3,Y3, X4,Y4: Double): TPath;
165 var
166   txt: TvText;
167 begin
168   if APage.UseTopLeftCoordinates then begin
169     Y1 := PAGE_SIZE - Y1;
170     Y2 := PAGE_SIZE - Y2;
171     Y3 := PAGE_SIZE - Y3;
172     Y4 := PAGE_SIZE - Y4;
173   end;
174   APage.StartPath(X1, Y1);
175   APage.AddBezierToPath(X2,Y2, X3,Y3, X4,Y4);
176   Result := APage.EndPath;
177   Result.Pen := StdPen;
178 
179   APage.StartPath(X1, Y1);
180   APage.AddLineToPath(X2, Y2);
181   APage.Endpath.Pen.Color := colRed;
182 
183   APage.StartPath(X4,Y4);
184   APage.AddLineToPath(X3, Y3);
185   APage.EndPath.Pen.Color := colRed;
186 
187   txt := TvText.Create(APage);
188   txt.Value.Add('1');
189   txt.X := X1;
190   txt.Y := Y1;
191   txt.Font.Color := colRed;
192   APage.AddEntity(txt);
193 
194   txt := TvText.Create(APage);
195   txt.Value.Add('2');
196   txt.X := X2;
197   txt.Y := Y2;
198   txt.Font.Color := colRed;
199   APage.AddEntity(txt);
200 
201   txt := TvText.Create(APage);
202   txt.Value.Add('3');
203   txt.X := X3;
204   txt.Y := Y3;
205   txt.Font.Color := colRed;
206   APage.AddEntity(txt);
207 
208   txt := TvText.Create(APage);
209   txt.Value.Add('4');
210   txt.X := X4;
211   txt.Y := Y4;
212   txt.Font.Color := colRed;
213   APage.AddEntity(txt);
214 end;
215 
216 
217 { Brushes }
218 
219 function CreateSimpleBrush(AStyle: TFPBrushStyle): TvBrush;
220 begin
221   Result := CreateSimpleBrush(AStyle, colBlack);
222 end;
223 
224 function CreateSimpleBrush(AStyle: TFPBrushStyle; AColor: TFPColor): TvBrush;
225 begin
226   Result.Kind := bkSimpleBrush;
227   Result.Color := TFPColor(AColor);
228   Result.Style := AStyle;
229 end;
230 
231 function CreateLinearGradientBrush(AStartPt, AEndPt: T2DPoint;
232   AFlags: TvGradientFlags; AStartColor, AEndColor: TFPColor): TvBrush;
233 var
234   p1, p2: T2dPoint;
235   x1str, x2str, y1str, y2str: String;
236 begin
237   if AStartPt.Y = AEndPt.Y then
238     Result.Kind := bkHorizontalGradient
239   else if AStartPt.X = AEndPt.X then
240     Result.Kind := bkVerticalGradient
241   else
242     Result.Kind := bkOtherLinearGradient;
243   Result.Gradient_start := AStartPt;
244   Result.Gradient_end := AEndPt;
245   Result.Gradient_flags := AFlags;
246   SetLength(Result.Gradient_colors, 2);
247   Result.Gradient_colors[0].Color := AStartColor;
248   Result.Gradient_colors[0].Position := 0;
249   Result.Gradient_colors[1].Color := AEndColor;
250   Result.Gradient_colors[1].Position := 1;
251 end;
252 
253 function CreateRadialGradientBrush(CX, CY, R, FX, FY: Double;
254   AStartColor, AEndColor: TFPColor): TvBrush;
255 begin
256   Result.Kind := bkRadialGradient;
257   Result.Gradient_cx := CX;
258   Result.Gradient_cy := CY;
259   Result.Gradient_r := R;
260   Result.Gradient_fx := FX;
261   Result.Gradient_fy := FY;
262   SetLength(Result.Gradient_colors, 2);
263   Result.Gradient_colors[0].Color := AStartColor;
264   Result.Gradient_colors[0].Position := 0;
265   Result.Gradient_colors[1].Color := AEndColor;
266   Result.Gradient_colors[1].Position := 1;
267 end;
268 
269 
270 { Pen }
271 
272 function CreatePen(AStyle: TFPPenStyle; AWidth: Integer; AColor: TFPColor): TvPen;
273 begin
274   Result.Style := AStyle;
275   Result.Width := AWidth;
276   Result.Color := AColor;
277 end;
278 
279 
280 { Standardized objects }
281 
282 { A circle shifted up }
283 function CreateStdCircle(APage: TvVectorialPage): TvCircle;
284 const
285   CENTER_X = 50;
286   CENTER_Y = 55;  // y points up for this number
287   RADIUS = 40;
288 begin
289   if APage.UseTopLeftCoordinates then
290     Result := CreateCircle(APage, CENTER_X, PAGE_SIZE - CENTER_Y, RADIUS) else
291     Result := CreateCircle(APage, CENTER_X, CENTER_Y, RADIUS);
292   Result.Pen := StdPen;
293 end;
294 
295 { An ellipse shifted up }
296 function CreateStdEllipse(APage: TvVectorialPage): TvEllipse;
297 begin
298   Result := CreateEllipse(APage, 10, 30, 90, 80);
299     // CreateEllipse will invert the axis if needed
300   Result.Pen := StdPen;
301 end;
302 
303 { A rectangle shifted up }
304 function CreateStdRect(APage: TvVectorialPage): TvRectangle;
305 const
306   LEFT = 10;
307   RIGHT = 90;
308   TOP = 95;     // for bottom-up y axis
309   BOTTOM = 15;  // dto.
310 begin
311   Result := CreateRectangle(APage, LEFT, TOP, RIGHT, BOTTOM);
312     // CreateRect will invert the y axis if needed
313   Result.Pen := StdPen;
314 end;
315 
316 { A rounded rectangle shifted up }
317 function CreateStdRoundedRect(APage: TvVectorialPage): TvRectangle;
318 const
319   LEFT = 10;
320   RIGHT = 90;
321   TOP = 95;     // for bottom-up y axis
322   BOTTOM = 15;  // dto.
323   RX = 10;
324   RY = 10;
325 begin
326   Result := CreateRoundedRect(APage,LEFT, TOP, RIGHT, BOTTOM, RX, RY);
327     // CreateRect will invert the y axis if needed
328   Result.Pen := StdPen;
329 end;
330 
331 { A triangle as polygon, base line at bottom }
332 function CreateStdPolygon(APage: TvVectorialPage):TvPolygon;
333 var
334   pts: array[0..3] of T3DPoint;
335   i: Integer;
336 begin
337   pts[0] := Make3DPoint(10, 10);
338   pts[1] := Make3dPoint(90, 10);
339   pts[2] := Make3DPoint(50, 90);
340   pts[3] := pts[0];
341   if APage.UseTopLeftCoordinates then
342     for i:=0 to High(pts) do
343       pts[i].Y := PAGE_SIZE - pts[i].Y;
344   Result := CreatePolygon(APage, pts);
345   Result.Pen := StdPen;
346 end;
347 
348 { A star-like self-intersecting polygon, tip at bottom }
349 function CreateStdSelfIntersectingPolygon(APage: TvVectorialPage): TvPolygon;
350 var
351   pts: array[0..5] of T3DPoint;
352   i: Integer;
353 begin
354   pts[0] := Make3DPoint(50, 5);
355   pts[1] := Make3DPoint(20, 90);
356   pts[2] := Make3DPoint(95, 30);
357   pts[3] := Make3DPoint(5,  30);
358   pts[4] := Make3DPoint(80, 90);
359   pts[5] := Make3DPoint(50, 5);
360   if APage.UseTopLeftCoordinates then
361     for i:=0 to High(pts) do
362       pts[i].Y := PAGE_SIZE - pts[i].Y;
363   Result := CreatePolygon(APage, pts);
364   Result.Pen := StdPen;
365 end;
366 
367 function CreatePathWithHole(APage: TvVectorialPage): TPath;
368 const
369   OUTER_POINTS: array[0..4] of T2DPoint = (
370     (X:10; Y:5), (X:90; Y:5), (X:90; Y:90), (X:10; Y:90), (X:10; Y:5)
371   );
372   INNER_POINTS: array[0..4] of T2DPoint = (
373     (X:50; Y:45), (X:40; Y:55), (X:50; Y:65), (X:60; Y:55), (X:50; Y:45)
374   );
375 var
376   i: Integer;
377 begin
378   if APage.UseTopLeftCoordinates then begin
379     APage.StartPath(OUTER_POINTS[0].X, PAGE_SIZE - OUTER_POINTS[0].Y);
380     for i:=1 to High(OUTER_POINTS) do
381       APage.AddLineToPath(OUTER_POINTS[i].X, PAGE_SIZE - OUTER_POINTS[i].Y);
382     APage.AddMoveToPath(INNER_POINTS[0].X, PAGE_SIZE - INNER_POINTS[0].Y);
383     for i:=1 to High(INNER_POINTS) do
384       APage.AddLineToPath(INNER_POINTS[i].X, PAGE_SIZE - INNER_POINTS[i].Y);
385   end else begin
386     APage.StartPath(OUTER_POINTS[0].X, OUTER_POINTS[0].Y);
387     for i:=1 to High(OUTER_POINTS) do
388       APage.AddLineToPath(OUTER_POINTS[i].X, OUTER_POINTS[i].Y);
389     APage.AddMoveToPath(INNER_POINTS[0].X, INNER_POINTS[0].Y);
390     for i:=1 to High(INNER_POINTS) do
391       APage.AddLineToPath(INNER_POINTS[i].X, INNER_POINTS[i].Y);
392   end;
393   Result := APage.EndPath;
394   Result.Pen := StdPen;
395 end;
396   (*
397 { Quarter circle in quadrant I }
398 function CreateStdCircArcQ1(APage: TvVectorialPage;
399   Clockwise, Reverse: Boolean): TPath;
400 const
401   CX = 50.0;
402   CY = 55.0;
403   RX = 30.0;
404   RY = 30.0;
405   X1 = CX + RX;
406   Y1 = CY;
407   X2 = CX;
408   Y2 = CY + RY;
409 begin
410   if Reverse then
411     Result := CreateArc(APage, X2, Y2, X1, Y1, CX, CY, RX, RY, 0, Clockwise)
412   else
413     Result := CreateArc(APage, X1, Y1, X2, Y2, CX, CY, RX, RY, 0, Clockwise);
414 end;
415 
416 { Quarter circle reaching from quadrant I into quadrant II}
417 function CreateStdCircArcQ12(APage: TvVectorialPage;
418   Clockwise, Reverse: Boolean): TPath;
419 const
420   SQRT2 = 1.4142135623731;
421   CX = 50.0;
422   CY = 55.0;
423   RX = 30.0;
424   RY = 30.0;
425   X1 = CX + RX/SQRT2;
426   Y1 = CY + RY/SQRT2;
427   X2 = CX - RX/SQRT2;
428   Y2 = CY + RY/SQRT2;
429 begin
430   if Reverse then
431     Result := CreateArc(APage, X2, Y2, X1, Y1, CX, CY, RX, RY, 0, Clockwise)
432   else
433     Result := CreateArc(APage, X1, Y1, X2, Y2, CX, CY, RX, RY, 0, Clockwise);
434 end;
435 
436 { Quarter circle in quadrant II }
437 function CreateStdCircArcQ2(APage: TvVectorialPage; Clockwise: Boolean): TPath;
438 const
439   CX = 50.0;
440   CY = 55.0;
441   RX = 30.0;
442   RY = 30.0;
443   X1 = CX;
444   Y1 = CY + RY;
445   X2 = CX - RX;
446   Y2 = CY;
447 begin
448   if Reverse then
449     Result := CreateArc(APage, X2, Y2, X1, Y1, CX, CY, RX, RY, 0, Clockwise)
450   else
451     Result := CreateArc(APage, X1, Y1, X2, Y2, CX, CY, RX, RY, 0, Clockwise);
452 end;
453 
454 { Quarter circle reaching from quadrant II into quadrant III}
455 function CreateStdCircArcQ23(APage: TvVectorialPage; Clockwise: Boolean): TPath;
456 const
457   SQRT2 = 1.4142135623731;
458   CX = 50.0;
459   CY = 55.0;
460   RX = 30.0;
461   RY = 30.0;
462   X1 = CX - RX/SQRT2;
463   Y1 = CY + RY/SQRT2;
464   X2 = CX - RX/SQRT2;
465   Y2 = CY - RY/SQRT2;
466 begin
467   if Reverse then
468     Result := CreateArc(APage, X2, Y2, X1, Y1, CX, CY, RX, RY, 0, Clockwise)
469   else
470     Result := CreateArc(APage, X1, Y1, X2, Y2, CX, CY, RX, RY, 0, Clockwise);
471 end;
472 
473 { Quarter circle in quadrant III }
474 function CreateStdCircArcQ3(APage: TvVectorialPage; Clockwise: Boolean): TPath;
475 const
476   CX = 50.0;
477   CY = 55.0;
478   RX = 30.0;
479   RY = 30.0;
480   X1 = CX - RX;
481   Y1 = CY;
482   X2 = CX;
483   Y2 = CY - RY;
484 begin
485   if Reverse then
486     Result := CreateArc(APage, X2, Y2, X1, Y1, CX, CY, RX, RY, 0, Clockwise)
487   else
488     Result := CreateArc(APage, X1, Y1, X2, Y2, CX, CY, RX, RY, 0, Clockwise);
489 end;
490 
491 { Quarter circle reaching from quadrant III into quadrant IV}
492 function CreateStdCircArcQ34(APage: TvVectorialPage; Clockwise: Boolean): TPath;
493 const
494   SQRT2 = 1.4142135623731;
495   CX = 50.0;
496   CY = 55.0;
497   RX = 30.0;
498   RY = 30.0;
499   X1 = CX - RX/SQRT2;
500   Y1 = CY - RY/SQRT2;
501   X2 = CX + RX/SQRT2;
502   Y2 = CY - RY/SQRT2;
503 begin
504   if Reverse then
505     Result := CreateArc(APage, X2, Y2, X1, Y1, CX, CY, RX, RY, 0, Clockwise)
506   else
507     Result := CreateArc(APage, X1, Y1, X2, Y2, CX, CY, RX, RY, 0, Clockwise);
508 end;
509 
510 { Quarter circle in quadrant IV }
511 function CreateStdCircArcQ4(APage: TvVectorialPage; Clockwise: Boolean): TPath;
512 const
513   CX = 50.0;
514   CY = 55.0;
515   RX = 30.0;
516   RY = 30.0;
517   X1 = CX;
518   Y1 = CY - RY;
519   X2 = CX + RX;
520   Y2 = CY;
521 begin
522   if Reverse then
523     Result := CreateArc(APage, X2, Y2, X1, Y1, CX, CY, RX, RY, 0, Clockwise)
524   else
525     Result := CreateArc(APage, X1, Y1, X2, Y2, CX, CY, RX, RY, 0, Clockwise);
526 end;
527 
528 { Quarter circle reaching from quadrant IV into quadrant I}
529 function CreateStdCircArcQ41(APage: TvVectorialPage; Clockwise: Boolean): TPath;
530 const
531   SQRT2 = 1.4142135623731;
532   CX = 50.0;
533   CY = 55.0;
534   RX = 30.0;
535   RY = 30.0;
536   X1 = CX + RX/SQRT2;
537   Y1 = CY - RY/SQRT2;
538   X2 = CX + RX/SQRT2;
539   Y2 = CY + RY/SQRT2;
540 begin
541   if Reverse then
542     Result := CreateArc(APage, X2, Y2, X1, Y1, CX, CY, RX, RY, 0, Clockwise)
543   else
544     Result := CreateArc(APage, X1, Y1, X2, Y2, CX, CY, RX, RY, 0, Clockwise);
545 end;
546 
547 function CreateStdEllArcQ1(APage: TvVectorialPage;
548   Clockwise, Reverse: Boolean; Angle: Double): TPath;
549 const
550   SQRT2 = 1.4142135623731;
551   CX = 50.0;
552   CY = 55.0;
553   RX = 30.0;
554   RY = 20.0;
555   X1 = CX + RX;
556   Y1 = CY;
557   X2 = CX;
558   Y2 = CY + RY;
559 begin
560   if Reverse then
561     Result := CreateArc(APage, X2, Y2, X1, Y1, CX, CY, RX, RY, Angle, Clockwise)
562   else
563     Result := CreateArc(APage, X1, Y1, X2, Y2, CX, CY, RX, RY, Angle, Clockwise);
564 end;
565 
566 function CreateStdEllArcQ12(APage: TvVectorialPage;
567   Clockwise, Reverse: Boolean; Angle: Double): TPath;
568 const
569   SQRT2 = 1.4142135623731;
570   CX = 50.0;
571   CY = 55.0;
572   RX = 30.0;
573   RY = 20.0;
574   X1 = CX + RX/SQRT2;
575   Y1 = CY + RY/SQRT2;
576   X2 = CX - RX/SQRT2;
577   Y2 = CY + RY/SQRT2;
578 begin
579   if Reverse then
580     Result := CreateArc(APage, X2, Y2, X1, Y1, CX, CY, RX, RY, Angle, Clockwise)
581   else
582     Result := CreateArc(APage, X1, Y1, X2, Y2, CX, CY, RX, RY, Angle, Clockwise);
583 end;
584 
585 function CreateStdEllArcQ2(APage: TvVectorialPage;
586   Clockwise, Reverse: Boolean; Angle: Double): TPath;
587 const
588   SQRT2 = 1.4142135623731;
589   CX = 50.0;
590   CY = 55.0;
591   RX = 30.0;
592   RY = 20.0;
593   X1 = CX;
594   Y1 = CY + RY;
595   X2 = CX - RX;
596   Y2 = CY;
597 begin
598   if Reverse then
599     Result := CreateArc(APage, X2, Y2, X1, Y1, CX, CY, RX, RY, Angle, Clockwise)
600   else
601     Result := CreateArc(APage, X1, Y1, X2, Y2, CX, CY, RX, RY, Angle, Clockwise);
602 end;
603 
604 function CreateStdEllArcQ23(APage: TvVectorialPage;
605   Clockwise, Reverse: Boolean; Angle: Double): TPath;
606 const
607   SQRT2 = 1.4142135623731;
608   CX = 50.0;
609   CY = 55.0;
610   RX = 30.0;
611   RY = 20.0;
612   X1 = CX - RX/SQRT2;
613   Y1 = CY + RY/SQRT2;
614   X2 = CX - RX/SQRT2;
615   Y2 = CY - RY/SQRT2;
616 begin
617   if Reverse then
618     Result := CreateArc(APage, X2, Y2, X1, Y1, CX, CY, RX, RY, Angle, Clockwise)
619   else
620     Result := CreateArc(APage, X1, Y1, X2, Y2, CX, CY, RX, RY, Angle, Clockwise);
621 end;
622 
623 function CreateStdEllArcQ3(APage: TvVectorialPage;
624   Clockwise, Reverse: Boolean; Angle: Double): TPath;
625 const
626   SQRT2 = 1.4142135623731;
627   CX = 50.0;
628   CY = 55.0;
629   RX = 30.0;
630   RY = 20.0;
631   X1 = CX - RX;
632   Y1 = CY;
633   X2 = CX;
634   Y2 = CY - RY;
635 begin
636   if Reverse then
637     Result := CreateArc(APage, X2, Y2, X1, Y1, CX, CY, RX, RY, Angle, Clockwise)
638   else
639     Result := CreateArc(APage, X1, Y1, X2, Y2, CX, CY, RX, RY, Angle, Clockwise);
640 end;
641 
642 function CreateStdEllArcQ34(APage: TvVectorialPage;
643   Clockwise, Reverse: Boolean; Angle: Double): TPath;
644 const
645   SQRT2 = 1.4142135623731;
646   CX = 50.0;
647   CY = 55.0;
648   RX = 30.0;
649   RY = 20.0;
650   X1 = CX - RX/SQRT2;
651   Y1 = CY - RY/SQRT2;
652   X2 = CX + RX/SQRT2;
653   Y2 = CY - RY/SQRT2;
654 begin
655   if Reverse then
656     Result := CreateArc(APage, X2, Y2, X1, Y1, CX, CY, RX, RY, Angle, Clockwise)
657   else
658     Result := CreateArc(APage, X1, Y1, X2, Y2, CX, CY, RX, RY, Angle, Clockwise);
659 end;
660 
661 function CreateStdEllArcQ4(APage: TvVectorialPage;
662   Clockwise, Reverse: Boolean; Angle: Double): TPath;
663 const
664   SQRT2 = 1.4142135623731;
665   CX = 50.0;
666   CY = 55.0;
667   RX = 30.0;
668   RY = 20.0;
669   X1 = CX;
670   Y1 = CY - RY;
671   X2 = CX + RX;
672   Y2 = CY;
673 begin
674   if Reverse then
675     Result := CreateArc(APage, X2, Y2, X1, Y1, CX, CY, RX, RY, Angle, Clockwise)
676   else
677     Result := CreateArc(APage, X1, Y1, X2, Y2, CX, CY, RX, RY, Angle, Clockwise);
678 end;
679 
680 function CreateStdEllArcQ41(APage: TvVectorialPage;
681   Clockwise, Reverse: Boolean; Angle: Double): TPath;
682 const
683   SQRT2 = 1.4142135623731;
684   CX = 50.0;
685   CY = 55.0;
686   RX = 30.0;
687   RY = 20.0;
688   X1 = CX + RX/SQRT2;
689   Y1 = CY - RY/SQRT2;
690   X2 = CX + RX/SQRT2;
691   Y2 = CY + RY/SQRT2;
692 begin
693   if Reverse then
694     Result := CreateArc(APage, X2, Y2, X1, Y1, CX, CY, RX, RY, Angle, Clockwise)
695   else
696     Result := CreateArc(APage, X1, Y1, X2, Y2, CX, CY, RX, RY, Angle, Clockwise);
697 end;
698     *)
699 
700 { ---- }
701 
702 function StdSolidBrush: TvBrush;
703 begin
704   Result := CreateSimpleBrush(bsSolid, colRed);
705 end;
706 
707 function StdHorizGradientBrush: TvBrush;
708 begin
709   Result := CreateLinearGradientBrush(Point2D(0, 0), Point2D(1, 0),
710     [gfRelStartX, gfRelEndX, gfRelStartY, gfRelEndY],
711     colBlue, colWhite);
712 end;
713 
714 { A vertical gradient, yellow at top, red at bottom }
715 function StdVertGradientBrush: TvBrush;
716 var
717   P1, P2: T2DPoint;
718 begin
719   {if APage.UseTopLeftCoordinates then begin
720     P1 := Point2D(0, 1);
721     P2 := Point2D(0, 0);
722   end else
723   }
724   begin
725     P1 := Point2D(0, 0);
726     P2 := Point2D(0, 1);
727   end;
728   Result := CreateLinearGradientBrush(P1, P2,
729     [gfRelStartX, gfRelEndX, gfRelStartY, gfRelEndY],
730     colYellow, colRed);
731 end;
732 
733 { A diagonal gradient running from bottom/left (yellow) to top/right (red) }
734 function StdLinearGradientBrush: TvBrush;
735 var
736   P1, P2: T2DPoint;
737 begin
738   {
739   if APage.UseTopLeftCoordinates then begin
740     P1 := Point2D(0, 1);
741     P2 := Point2D(1, 0);
742   end else
743   }
744   begin
745     P1 := Point2D(0, 0);
746     P2 := Point2D(1, 1);
747   end;
748   Result := CreateLinearGradientBrush(Point2D(0, 0), Point2D(1, 1),
749     [gfRelStartX, gfRelEndX, gfRelStartY, gfRelEndY],
750     colYellow, colRed);
751 end;
752 
753 function StdRadialGradientBrush: TvBrush;
754 begin
755   Result := CreateRadialGradientBrush(0.5, 0.5, 0.5, 0.5, 0.5,
756     colRed, colYellow);
757 end;
758 
759 function StdPen: TvPen;
760 begin
761   Result := CreatePen(psSolid, 4, colBlack);
762 end;
763 
764 end.
765 
766