Changeset 521 for GraphicTest/Packages/bgrabitmap/bgratypewriter.pas
- Timestamp:
- Apr 17, 2019, 12:58:41 AM (5 years ago)
- Location:
- GraphicTest
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
GraphicTest
- Property svn:ignore
-
old new 8 8 GraphicTest.lps 9 9 GraphicTest.dbg 10 heaptrclog.trc
-
- Property svn:ignore
-
GraphicTest/Packages/bgrabitmap/bgratypewriter.pas
r494 r521 35 35 end; 36 36 37 TGlyphPointCurveMode= (cmAuto, cmCurve, cmAngle); 38 37 TGlyphPointCurveMode= TEasyBezierCurveMode; 38 39 const 40 cmAuto = TEasyBezierCurveMode.cmAuto; 41 cmCurve = TEasyBezierCurveMode.cmCurve; 42 cmAngle = TEasyBezierCurveMode.cmAngle; 43 44 type 39 45 { TBGRAPolygonalGlyph } 40 46 41 47 TBGRAPolygonalGlyph = class(TBGRAGlyph) 42 48 private 49 function GetClosed: boolean; 50 function GetMinimumDotProduct: single; 51 function GetPoint(AIndex: integer): TPointF; 52 function GetPointCount: integer; 53 procedure SetClosed(AValue: boolean); 54 procedure SetMinimumDotProduct(AValue: single); 55 procedure SetPoint(AIndex: integer; AValue: TPointF); 43 56 procedure SetQuadraticCurves(AValue: boolean); 44 57 protected 45 58 FQuadraticCurves: boolean; 46 Points: array of TPointF; 47 CurveMode: array of TGlyphPointCurveMode; 48 Curves: array of record 49 isCurvedToNext,isCurvedToPrevious: boolean; 50 Center,ControlPoint,NextCenter: TPointF; 51 end; 52 function MaybeCurve(start1,end1,start2,end2: integer): boolean; 53 procedure ComputeQuadraticCurves; 59 FEasyBezier: TEasyBezierCurve; 54 60 function ContentSize: integer; override; 55 61 function HeaderName: string; override; 56 62 procedure WriteContent(AStream: TStream); override; 57 63 procedure ReadContent(AStream: TStream); override; 64 function PointTransformMatrix(APoint: PPointF; AData: pointer): TPointF; 58 65 procedure Init; 59 66 public 60 67 Offset: TPointF; 61 Closed: boolean;62 MinimumDotProduct: single;63 68 constructor Create(AIdentifier: string); override; 64 69 constructor Create(AStream: TStream); override; 70 constructor Create(AStream: TStream; AQuadratic: boolean); 65 71 procedure SetPoints(const APoints: array of TPointF); overload; 66 72 procedure SetPoints(const APoints: array of TPointF; const ACurveMode: array of TGlyphPointCurveMode); overload; 67 73 procedure Path(ADest: IBGRAPath; AMatrix: TAffineMatrix); override; 68 74 property QuadraticCurves: boolean read FQuadraticCurves write SetQuadraticCurves; 75 property Closed: boolean read GetClosed write SetClosed; 76 property MinimumDotProduct: single read GetMinimumDotProduct write SetMinimumDotProduct; 77 property Point[AIndex: integer]: TPointF read GetPoint write SetPoint; 78 property PointCount: integer read GetPointCount; 69 79 end; 70 80 … … 193 203 { TBGRAPolygonalGlyph } 194 204 205 function TBGRAPolygonalGlyph.GetClosed: boolean; 206 begin 207 result := FEasyBezier.Closed; 208 end; 209 210 function TBGRAPolygonalGlyph.GetMinimumDotProduct: single; 211 begin 212 result := FEasyBezier.MinimumDotProduct; 213 end; 214 215 function TBGRAPolygonalGlyph.GetPoint(AIndex: integer): TPointF; 216 begin 217 result := FEasyBezier.Point[AIndex]; 218 end; 219 220 function TBGRAPolygonalGlyph.GetPointCount: integer; 221 begin 222 result := FEasyBezier.PointCount; 223 end; 224 225 procedure TBGRAPolygonalGlyph.SetClosed(AValue: boolean); 226 begin 227 FEasyBezier.Closed := AValue; 228 end; 229 230 procedure TBGRAPolygonalGlyph.SetMinimumDotProduct(AValue: single); 231 begin 232 FEasyBezier.MinimumDotProduct := AValue; 233 end; 234 235 procedure TBGRAPolygonalGlyph.SetPoint(AIndex: integer; AValue: TPointF); 236 begin 237 FEasyBezier.Point[AIndex] := AValue; 238 end; 239 195 240 procedure TBGRAPolygonalGlyph.SetQuadraticCurves(AValue: boolean); 196 241 begin 197 242 if FQuadraticCurves=AValue then Exit; 198 243 FQuadraticCurves:=AValue; 199 Curves := nil;200 end;201 202 function TBGRAPolygonalGlyph.MaybeCurve(start1,end1,start2,end2: integer): boolean;203 var204 u,v: TPointF;205 lu,lv: single;206 begin207 if (start1=-1) or (end1=-1) or (start2=-1) or (end2=-1) then208 begin209 result := false;210 exit;211 end;212 u := pointF(points[end1].x - points[start1].x, points[end1].y - points[start1].y);213 lu := sqrt(u*u);214 if lu <> 0 then u *= 1/lu;215 v := pointF(points[end2].x - points[start2].x, points[end2].y - points[start2].y);216 lv := sqrt(v*v);217 if lv <> 0 then v *= 1/lv;218 219 result := u*v > MinimumDotProduct;220 end;221 222 procedure TBGRAPolygonalGlyph.ComputeQuadraticCurves;223 var224 i,FirstPointIndex,NextPt,NextPt2: integer;225 begin226 setlength(Curves, length(points));227 FirstPointIndex := 0;228 for i := 0 to high(points) do229 Curves[i].isCurvedToPrevious := false;230 for i := 0 to high(points) do231 begin232 Curves[i].isCurvedToNext := false;233 Curves[i].Center := EmptyPointF;234 Curves[i].ControlPoint := EmptyPointF;235 Curves[i].NextCenter := EmptyPointF;236 237 if IsEmptyPointF(Points[i]) then238 begin239 FirstPointIndex := i+1;240 end else241 begin242 NextPt := i+1;243 if (NextPt = length(points)) or isEmptyPointF(points[NextPt]) then NextPt := FirstPointIndex;244 NextPt2 := NextPt+1;245 if (NextPt2 = length(points)) or isEmptyPointF(points[NextPt2]) then NextPt2 := FirstPointIndex;246 247 Curves[i].Center := (points[i]+points[NextPt])*0.5;248 Curves[i].NextCenter := (points[NextPt]+points[NextPt2])*0.5;249 Curves[i].ControlPoint := points[NextPt];250 251 if (i < high(points)-1) or Closed then252 begin253 case CurveMode[nextPt] of254 cmAuto: Curves[i].isCurvedToNext:= MaybeCurve(i,NextPt,NextPt,NextPt2);255 cmCurve: Curves[i].isCurvedToNext:= true;256 else Curves[i].isCurvedToNext:= false;257 end;258 Curves[NextPt].isCurvedToPrevious := Curves[i].isCurvedToNext;259 end;260 end;261 end;262 244 end; 263 245 264 246 function TBGRAPolygonalGlyph.ContentSize: integer; 265 247 begin 266 Result:= (inherited ContentSize) + sizeof(single)*2 + 4 + sizeof(single)*2* length(Points);248 Result:= (inherited ContentSize) + sizeof(single)*2 + 4 + sizeof(single)*2*PointCount; 267 249 end; 268 250 269 251 function TBGRAPolygonalGlyph.HeaderName: string; 270 252 begin 271 Result:='TBGRAPolygonalGlyph'; 253 if FQuadraticCurves then 254 Result:='TBGRAEasyBezierGlyph' 255 else 256 Result:='TBGRAPolygonalGlyph' 272 257 end; 273 258 … … 277 262 inherited WriteContent(AStream); 278 263 LEWritePointF(AStream, Offset); 279 LEWriteLongint(AStream,length(Points)); 280 for i := 0 to high(Points) do 281 LEWritePointF(AStream, Points[i]); 264 LEWriteLongint(AStream,PointCount); 265 for i := 0 to PointCount-1 do 266 LEWritePointF(AStream, FEasyBezier.Point[i]); 267 if FQuadraticCurves then 268 for i := 0 to PointCount-1 do 269 LEWriteLongint(AStream, ord(FEasyBezier.CurveMode[i])); 282 270 end; 283 271 … … 285 273 var i: integer; 286 274 tempPts: array of TPointF; 275 flags: LongInt; 287 276 begin 288 277 inherited ReadContent(AStream); … … 292 281 tempPts[i] := LEReadPointF(AStream); 293 282 SetPoints(tempPts); 283 if FQuadraticCurves then 284 begin 285 for i := 0 to high(tempPts) do 286 begin 287 flags := LEReadLongint(AStream); 288 FEasyBezier.CurveMode[i] := TEasyBezierCurveMode(flags and 255); 289 end; 290 end; 291 end; 292 293 function TBGRAPolygonalGlyph.PointTransformMatrix(APoint: PPointF; 294 AData: pointer): TPointF; 295 begin 296 result := TAffineMatrix(AData^) * APoint^; 294 297 end; 295 298 296 299 procedure TBGRAPolygonalGlyph.Init; 297 300 begin 301 FEasyBezier.Init; 298 302 Closed := True; 299 MinimumDotProduct := 0.707; 303 Offset := PointF(0,0); 304 FQuadraticCurves:= False; 300 305 end; 301 306 302 307 constructor TBGRAPolygonalGlyph.Create(AIdentifier: string); 303 308 begin 309 Init; 304 310 inherited Create(AIdentifier); 305 Offset := PointF(0,0); 311 end; 312 313 constructor TBGRAPolygonalGlyph.Create(AStream: TStream); 314 begin 306 315 Init; 307 end;308 309 constructor TBGRAPolygonalGlyph.Create(AStream: TStream);310 begin311 316 inherited Create(AStream); 317 end; 318 319 constructor TBGRAPolygonalGlyph.Create(AStream: TStream; AQuadratic: boolean); 320 begin 312 321 Init; 322 FQuadraticCurves:= AQuadratic; 323 inherited Create(AStream); 313 324 end; 314 325 315 326 procedure TBGRAPolygonalGlyph.SetPoints(const APoints: array of TPointF); 316 var i: integer; 317 begin 318 SetLength(Points,length(APoints)); 319 for i := 0 to high(points) do 320 points[i] := APoints[i]; 321 setlength(CurveMode, length(APoints)); 322 for i := 0 to high(CurveMode) do 323 CurveMode[i] := cmAuto; 324 Curves := nil; 327 begin 328 FEasyBezier.SetPoints(APoints, cmAuto); 325 329 end; 326 330 327 331 procedure TBGRAPolygonalGlyph.SetPoints(const APoints: array of TPointF; 328 332 const ACurveMode: array of TGlyphPointCurveMode); 329 var i: integer;330 333 begin 331 334 if length(APoints) <> length(ACurveMode) then 332 335 raise exception.Create('Dimension mismatch'); 333 SetLength(Points,length(APoints)); 334 for i := 0 to high(points) do 335 points[i] := APoints[i]; 336 setlength(CurveMode, length(ACurveMode)); 337 for i := 0 to high(CurveMode) do 338 CurveMode[i] := ACurveMode[i]; 339 Curves := nil; 336 FEasyBezier.SetPoints(APoints, ACurveMode); 340 337 end; 341 338 … … 343 340 var i: integer; 344 341 nextMove: boolean; 345 startCoord: TPointF; 346 347 begin 348 if Points = nil then exit; 349 350 if (Curves = nil) and FQuadraticCurves then ComputeQuadraticCurves; 351 nextMove := true; 342 begin 352 343 AMatrix := AMatrix*AffineMatrixTranslation(Offset.X,Offset.Y); 353 354 for i := 0 to high(Points) do 355 if isEmptyPointF(Points[i]) then 356 begin 357 if not nextMove then ADest.closePath; 358 nextMove := true; 359 end else 360 if FQuadraticCurves then 361 begin 362 with Curves[i] do 344 if not FQuadraticCurves then 345 begin 346 nextMove := true; 347 for i := 0 to PointCount-1 do 348 if isEmptyPointF(Point[i]) then 349 begin 350 if not nextMove and Closed then ADest.closePath; 351 nextMove := true; 352 end else 363 353 begin 364 354 if nextMove then 365 355 begin 366 if not isCurvedToPrevious then 367 startCoord := Points[i] 368 else 369 startCoord := Center; 370 ADest.moveTo(AMatrix*startCoord); 356 ADest.moveTo(AMatrix*Point[i]); 371 357 nextMove := false; 372 358 end else 373 if not isCurvedToPrevious then 374 ADest.lineTo(AMatrix*Points[i]); 375 376 if isCurvedToNext then 377 begin 378 if not isCurvedToPrevious then ADest.lineTo(AMatrix*Center); 379 ADest.quadraticCurveTo(AMatrix*ControlPoint,AMatrix*NextCenter); 380 end; 359 ADest.lineTo(AMatrix*Point[i]); 381 360 end; 382 end else 383 begin 384 if nextMove then 385 begin 386 ADest.moveTo(AMatrix*Points[i]); 387 nextMove := false; 388 end else 389 begin 390 ADest.lineTo(AMatrix*Points[i]); 391 end; 392 end; 393 if not nextmove then 394 ADest.closePath; 361 if not nextmove and Closed then ADest.closePath; 362 end else 363 FEasyBezier.CopyToPath(ADest, @PointTransformMatrix, @AMatrix); 395 364 end; 396 365 … … 473 442 if lName = 'TBGRAPolygonalGlyph' then 474 443 result := TBGRAPolygonalGlyph.Create(AStream) 444 else if lName = 'TBGRAEasyBezierGlyph' then 445 result := TBGRAPolygonalGlyph.Create(AStream, true) 475 446 else if lName = 'TBGRAGlyph' then 476 447 result := TBGRAGlyph.Create(AStream)
Note:
See TracChangeset
for help on using the changeset viewer.