GR32_Transforms.pas 59 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168
  1. unit GR32_Transforms;
  2. (* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1 or LGPL 2.1 with linking exception
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * Alternatively, the contents of this file may be used under the terms of the
  16. * Free Pascal modified version of the GNU Lesser General Public License
  17. * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
  18. * of this license are applicable instead of those above.
  19. * Please see the file LICENSE.txt for additional information concerning this
  20. * license.
  21. *
  22. * The Original Code is Graphics32
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Alex A. Denisov
  26. *
  27. * Portions created by the Initial Developer are Copyright (C) 2000-2009
  28. * the Initial Developer. All Rights Reserved.
  29. *
  30. * Contributor(s):
  31. * Andre Beckedorf <[email protected]>
  32. * Mattias Andersson <[email protected]>
  33. * J. Tulach <[email protected]>
  34. * Michael Hansen <[email protected]>
  35. * Peter Larson
  36. *
  37. * ***** END LICENSE BLOCK ***** *)
  38. interface
  39. {$I GR32.inc}
  40. uses
  41. {$IFDEF FPC}
  42. LCLIntf,
  43. {$ELSE}
  44. Windows,
  45. {$ENDIF}
  46. SysUtils, Classes, Types, GR32, GR32_VectorMaps, GR32_Rasterizers;
  47. type
  48. ETransformError = class(Exception);
  49. ETransformNotImplemented = class(Exception);
  50. type
  51. TFloatMatrix = array [0..2, 0..2] of TFloat; // 3x3 TFloat precision
  52. TFixedMatrix = array [0..2, 0..2] of TFixed; // 3x3 fixed precision
  53. const
  54. IdentityMatrix: TFloatMatrix = (
  55. (1, 0, 0),
  56. (0, 1, 0),
  57. (0, 0, 1));
  58. type
  59. TVector3f = array [0..2] of TFloat;
  60. TVector3i = array [0..2] of Integer;
  61. // Matrix conversion routines
  62. function FixedMatrix(const FloatMatrix: TFloatMatrix): TFixedMatrix; overload;
  63. function FloatMatrix(const FixedMatrix: TFixedMatrix): TFloatMatrix; overload;
  64. procedure Adjoint(var M: TFloatMatrix);
  65. function Determinant(const M: TFloatMatrix): TFloat;
  66. procedure Scale(var M: TFloatMatrix; Factor: TFloat);
  67. procedure Invert(var M: TFloatMatrix);
  68. function Mult(const M1, M2: TFloatMatrix): TFloatMatrix;
  69. function VectorTransform(const M: TFloatMatrix; const V: TVector3f): TVector3f;
  70. type
  71. TTransformation = class(TNotifiablePersistent)
  72. private
  73. FSrcRect: TFloatRect;
  74. procedure SetSrcRect(const Value: TFloatRect);
  75. protected
  76. TransformValid: Boolean;
  77. procedure PrepareTransform; virtual;
  78. procedure ReverseTransformInt(DstX, DstY: Integer; out SrcX, SrcY: Integer); virtual;
  79. procedure ReverseTransformFixed(DstX, DstY: TFixed; out SrcX, SrcY: TFixed); virtual;
  80. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); virtual;
  81. procedure TransformInt(SrcX, SrcY: Integer; out DstX, DstY: Integer); virtual;
  82. procedure TransformFixed(SrcX, SrcY: TFixed; out DstX, DstY: TFixed); virtual;
  83. procedure TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat); virtual;
  84. public
  85. constructor Create; virtual;
  86. procedure Changed; override;
  87. function HasTransformedBounds: Boolean; virtual;
  88. function GetTransformedBounds: TFloatRect; overload;
  89. function GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect; overload; virtual;
  90. function ReverseTransform(const P: TPoint): TPoint; overload; virtual;
  91. function ReverseTransform(const P: TFixedPoint): TFixedPoint; overload; virtual;
  92. function ReverseTransform(const P: TFloatPoint): TFloatPoint; overload; virtual;
  93. function Transform(const P: TPoint): TPoint; overload; virtual;
  94. function Transform(const P: TFixedPoint): TFixedPoint; overload; virtual;
  95. function Transform(const P: TFloatPoint): TFloatPoint; overload; virtual;
  96. property SrcRect: TFloatRect read FSrcRect write SetSrcRect;
  97. end;
  98. TTransformationClass = class of TTransformation;
  99. TNestedTransformation = class(TTransformation)
  100. private
  101. FItems: TList;
  102. FOwner: TPersistent;
  103. function GetCount: Integer;
  104. function GetItem(Index: Integer): TTransformation;
  105. procedure SetItem(Index: Integer; const Value: TTransformation);
  106. protected
  107. procedure PrepareTransform; override;
  108. procedure ReverseTransformFixed(DstX, DstY: TFixed; out SrcX, SrcY: TFixed); override;
  109. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  110. procedure TransformFixed(SrcX, SrcY: TFixed; out DstX, DstY: TFixed); override;
  111. procedure TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat); override;
  112. public
  113. constructor Create; override;
  114. destructor Destroy; override;
  115. function Add(ItemClass: TTransformationClass): TTransformation;
  116. procedure Clear;
  117. procedure Delete(Index: Integer);
  118. function Insert(Index: Integer; ItemClass: TTransformationClass): TTransformation;
  119. property Owner: TPersistent read FOwner;
  120. property Count: Integer read GetCount;
  121. property Items[Index: Integer]: TTransformation read GetItem write SetItem; default;
  122. end;
  123. T3x3Transformation = class(TTransformation)
  124. protected
  125. FMatrix, FInverseMatrix: TFloatMatrix;
  126. FFixedMatrix, FInverseFixedMatrix: TFixedMatrix;
  127. procedure PrepareTransform; override;
  128. procedure ReverseTransformFixed(DstX, DstY: TFixed; out SrcX, SrcY: TFixed); override;
  129. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  130. procedure TransformFixed(SrcX, SrcY: TFixed; out DstX, DstY: TFixed); override;
  131. procedure TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat); override;
  132. public
  133. property Matrix: TFloatMatrix read FMatrix;
  134. end;
  135. TAffineTransformation = class(T3x3Transformation)
  136. private
  137. FStack: ^TFloatMatrix;
  138. FStackLevel: Integer;
  139. public
  140. constructor Create; override;
  141. function GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect; override;
  142. procedure Push;
  143. procedure Pop;
  144. procedure Clear; overload;
  145. procedure Clear(BaseMatrix: TFloatMatrix); overload;
  146. procedure Rotate(Alpha: TFloat); overload; // degrees
  147. procedure Rotate(Cx, Cy, Alpha: TFloat); overload; // degrees
  148. procedure Skew(Fx, Fy: TFloat);
  149. procedure Scale(Sx, Sy: TFloat); overload;
  150. procedure Scale(Value: TFloat); overload;
  151. procedure Translate(Dx, Dy: TFloat);
  152. end;
  153. TProjectiveTransformation = class(T3x3Transformation)
  154. private
  155. FQuadX: array [0..3] of TFloat;
  156. FQuadY: array [0..3] of TFloat;
  157. procedure SetX(Index: Integer; const Value: TFloat); {$IFDEF UseInlining} inline; {$ENDIF}
  158. procedure SetY(Index: Integer; const Value: TFloat); {$IFDEF UseInlining} inline; {$ENDIF}
  159. function GetX(Index: Integer): TFloat; {$IFDEF UseInlining} inline; {$ENDIF}
  160. function GetY(Index: Integer): TFloat; {$IFDEF UseInlining} inline; {$ENDIF}
  161. protected
  162. procedure PrepareTransform; override;
  163. procedure ReverseTransformFixed(DstX, DstY: TFixed; out SrcX, SrcY: TFixed); override;
  164. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  165. procedure TransformFixed(SrcX, SrcY: TFixed; out DstX, DstY: TFixed); override;
  166. procedure TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat); override;
  167. public
  168. function GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect; override;
  169. property X[Index: Integer]: TFloat read GetX write SetX;
  170. property Y[index: Integer]: TFloat read GetX write SetY;
  171. published
  172. property X0: TFloat index 0 read GetX write SetX;
  173. property X1: TFloat index 1 read GetX write SetX;
  174. property X2: TFloat index 2 read GetX write SetX;
  175. property X3: TFloat index 3 read GetX write SetX;
  176. property Y0: TFloat index 0 read GetY write SetY;
  177. property Y1: TFloat index 1 read GetY write SetY;
  178. property Y2: TFloat index 2 read GetY write SetY;
  179. property Y3: TFloat index 3 read GetY write SetY;
  180. end;
  181. TTwirlTransformation = class(TTransformation)
  182. private
  183. Frx, Fry: TFloat;
  184. FTwirl: TFloat;
  185. procedure SetTwirl(const Value: TFloat);
  186. protected
  187. procedure PrepareTransform; override;
  188. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  189. public
  190. constructor Create; override;
  191. function GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect; override;
  192. published
  193. property Twirl: TFloat read FTwirl write SetTwirl;
  194. end;
  195. TBloatTransformation = class(TTransformation)
  196. private
  197. FBloatPower: TFloat;
  198. FBP: TFloat;
  199. FPiW, FPiH: TFloat;
  200. procedure SetBloatPower(const Value: TFloat);
  201. protected
  202. procedure PrepareTransform; override;
  203. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  204. procedure TransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  205. public
  206. constructor Create; override;
  207. published
  208. property BloatPower: TFloat read FBloatPower write SetBloatPower;
  209. end;
  210. TDisturbanceTransformation = class(TTransformation)
  211. private
  212. FDisturbance: TFloat;
  213. procedure SetDisturbance(const Value: TFloat);
  214. protected
  215. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  216. public
  217. function GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect; override;
  218. published
  219. property Disturbance: TFloat read FDisturbance write SetDisturbance;
  220. end;
  221. TFishEyeTransformation = class(TTransformation)
  222. private
  223. Frx, Fry: TFloat;
  224. Faw, Fsr: TFloat;
  225. Sx, Sy: TFloat;
  226. FMinR: TFloat;
  227. protected
  228. procedure PrepareTransform; override;
  229. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  230. end;
  231. TPolarTransformation = class(TTransformation)
  232. private
  233. FDstRect: TFloatRect;
  234. FPhase: TFloat;
  235. Sx, Sy, Cx, Cy, Dx, Dy, Rt, Rt2, Rr, Rcx, Rcy: TFloat;
  236. procedure SetDstRect(const Value: TFloatRect);
  237. procedure SetPhase(const Value: TFloat);
  238. protected
  239. procedure PrepareTransform; override;
  240. procedure TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat); override;
  241. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  242. public
  243. property DstRect: TFloatRect read FDstRect write SetDstRect;
  244. property Phase: TFloat read FPhase write SetPhase;
  245. end;
  246. TPathTransformation = class(TTransformation)
  247. private
  248. FTopLength: TFloat;
  249. FBottomLength: TFloat;
  250. FBottomCurve: TArrayOfFloatPoint;
  251. FTopCurve: TArrayOfFloatPoint;
  252. FTopHypot, FBottomHypot: array of record Dist, RecDist: TFloat end;
  253. procedure SetBottomCurve(const Value: TArrayOfFloatPoint);
  254. procedure SetTopCurve(const Value: TArrayOfFloatPoint);
  255. protected
  256. rdx, rdy: TFloat;
  257. procedure PrepareTransform; override;
  258. procedure TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat); override;
  259. public
  260. destructor Destroy; override;
  261. property TopCurve: TArrayOfFloatPoint read FTopCurve write SetTopCurve;
  262. property BottomCurve: TArrayOfFloatPoint read FBottomCurve write SetBottomCurve;
  263. end;
  264. TRadialDistortionTransformation = class(TTransformation)
  265. protected
  266. FCoefficient1, FCoefficient2, FScale: TFloat;
  267. FFocalPoint: TFloatPoint;
  268. r_0, r_tgt_max, r_tgt_min: Single;
  269. FMapElements: Integer;
  270. Map: Array of TFloat;
  271. function LookUpReverseMap(const r_tgt: TFloat): TFloat;
  272. procedure SetCoefficient1(const Value: TFloat);
  273. procedure SetCoefficient2(const Value: TFloat);
  274. procedure SetScale(const Value: TFloat);
  275. procedure SetMapElements(const Value: Integer);
  276. procedure PrepareReverseMap;
  277. procedure PrepareTransform; override;
  278. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  279. procedure TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat); override;
  280. public
  281. constructor Create; override;
  282. function HasTransformedBounds: Boolean; override;
  283. published
  284. property Coefficient1: TFloat read FCoefficient1 write SetCoefficient1;
  285. property Coefficient2: TFloat read FCoefficient2 write SetCoefficient2;
  286. property Scale: TFloat read FScale write SetScale;
  287. property MapElements: Integer read FMapElements write SetMapElements;
  288. end;
  289. TRemapTransformation = class(TTransformation)
  290. private
  291. FVectorMap: TVectorMap;
  292. FScalingFixed: TFixedVector;
  293. FScalingFloat: TFloatVector;
  294. FCombinedScalingFixed: TFixedVector;
  295. FCombinedScalingFloat: TFloatVector;
  296. FSrcTranslationFixed: TFixedVector;
  297. FSrcScaleFixed: TFixedVector;
  298. FDstTranslationFixed: TFixedVector;
  299. FDstScaleFixed: TFixedVector;
  300. FSrcTranslationFloat: TFloatVector;
  301. FSrcScaleFloat: TFloatVector;
  302. FDstTranslationFloat: TFloatVector;
  303. FDstScaleFloat: TFloatVector;
  304. FOffsetFixed : TFixedVector;
  305. FOffsetInt : TPoint;
  306. FMappingRect: TFloatRect;
  307. FOffset: TFloatVector;
  308. procedure SetMappingRect(Rect: TFloatRect);
  309. procedure SetOffset(const Value: TFloatVector);
  310. protected
  311. procedure PrepareTransform; override;
  312. procedure ReverseTransformInt(DstX, DstY: Integer; out SrcX, SrcY: Integer); override;
  313. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  314. procedure ReverseTransformFixed(DstX, DstY: TFixed; out SrcX, SrcY: TFixed); override;
  315. public
  316. constructor Create; override;
  317. destructor Destroy; override;
  318. function HasTransformedBounds: Boolean; override;
  319. function GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect; override;
  320. procedure Scale(Sx, Sy: TFloat);
  321. property MappingRect: TFloatRect read FMappingRect write SetMappingRect;
  322. property Offset: TFloatVector read FOffset write SetOffset;
  323. property VectorMap: TVectorMap read FVectorMap write FVectorMap;
  324. end;
  325. function TransformPoints(Points: TArrayOfArrayOfFixedPoint; Transformation: TTransformation): TArrayOfArrayOfFixedPoint;
  326. procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation; Reverse: boolean = True); overload;
  327. procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation;
  328. const DstClip: TRect; Reverse: boolean = True); overload;
  329. procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation;
  330. Rasterizer: TRasterizer; Reverse: boolean = True); overload;
  331. procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation;
  332. Rasterizer: TRasterizer; const DstClip: TRect; Reverse: boolean = True); overload;
  333. procedure RasterizeTransformation(Vectormap: TVectormap;
  334. Transformation: TTransformation; DstRect: TRect;
  335. CombineMode: TVectorCombineMode = vcmAdd;
  336. CombineCallback: TVectorCombineEvent = nil);
  337. procedure SetBorderTransparent(ABitmap: TCustomBitmap32; ARect: TRect);
  338. { FullEdge controls how the bitmap is resampled }
  339. var
  340. FullEdge: Boolean = True;
  341. resourcestring
  342. RCStrReverseTransformationNotImplemented = 'Reverse transformation is not implemented in %s.';
  343. RCStrForwardTransformationNotImplemented = 'Forward transformation is not implemented in %s.';
  344. RCStrTopBottomCurveNil = 'Top or bottom curve is nil';
  345. implementation
  346. uses
  347. Math, GR32_Blend, GR32_LowLevel, GR32_Math, GR32_Bindings,
  348. GR32_Resamplers, GR32_Geometry;
  349. resourcestring
  350. RCStrSrcRectIsEmpty = 'SrcRect is empty!';
  351. RCStrMappingRectIsEmpty = 'MappingRect is empty!';
  352. RStrStackEmpty = 'Stack empty';
  353. type
  354. {provides access to proctected members of TCustomBitmap32 by typecasting}
  355. TTransformationAccess = class(TTransformation);
  356. var
  357. DET32: function(a1, a2, b1, b2: Single): Single;
  358. DET64: function(a1, a2, b1, b2: Double): Double;
  359. { A bit of linear algebra }
  360. function DET32_Pas(a1, a2, b1, b2: Single): Single; overload;
  361. begin
  362. Result := a1 * b2 - a2 * b1;
  363. end;
  364. function DET64_Pas(a1, a2, b1, b2: Double): Double; overload;
  365. begin
  366. Result := a1 * b2 - a2 * b1;
  367. end;
  368. {$IFNDEF PUREPASCAL}
  369. function DET32_ASM(a1, a2, b1, b2: Single): Single; overload; {$IFDEF FPC}assembler; {$IFDEF CPU64}nostackframe;{$ENDIF}{$ENDIF}
  370. asm
  371. {$IFDEF CPU64}
  372. MULSS XMM0, XMM3
  373. MULSS XMM1, XMM2
  374. ADDSS XMM0, XMM1
  375. {$ELSE}
  376. FLD A1.Single
  377. FMUL B2.Single
  378. FLD A2.Single
  379. FMUL B1.Single
  380. FSUBP
  381. {$ENDIF}
  382. end;
  383. function DET64_ASM(a1, a2, b1, b2: Double): Double; overload;
  384. asm
  385. {$IFDEF CPU64}
  386. MULSD XMM0, XMM3
  387. MULSD XMM1, XMM2
  388. ADDSD XMM0, XMM1
  389. {$ELSE}
  390. FLD A1.Double
  391. FMUL B2.Double
  392. FLD A2.Double
  393. FMUL B1.Double
  394. FSUBP
  395. {$ENDIF}
  396. end;
  397. {$ENDIF}
  398. { implementation of detereminant for TFloat precision }
  399. function _DET(a1, a2, b1, b2: TFloat): TFloat; overload; {$IFDEF UseInlining} inline; {$ENDIF}
  400. begin
  401. Result := a1 * b2 - a2 * b1;
  402. end;
  403. function _DET(a1, a2, a3, b1, b2, b3, c1, c2, c3: TFloat): TFloat; overload; {$IFDEF UseInlining} inline; {$ENDIF}
  404. begin
  405. Result :=
  406. a1 * (b2 * c3 - b3 * c2) -
  407. b1 * (a2 * c3 - a3 * c2) +
  408. c1 * (a2 * b3 - a3 * b2);
  409. end;
  410. procedure Adjoint(var M: TFloatMatrix);
  411. var
  412. Tmp: TFloatMatrix;
  413. begin
  414. Tmp := M;
  415. M[0,0] := _DET(Tmp[1,1], Tmp[1,2], Tmp[2,1], Tmp[2,2]);
  416. M[0,1] := -_DET(Tmp[0,1], Tmp[0,2], Tmp[2,1], Tmp[2,2]);
  417. M[0,2] := _DET(Tmp[0,1], Tmp[0,2], Tmp[1,1], Tmp[1,2]);
  418. M[1,0] := -_DET(Tmp[1,0], Tmp[1,2], Tmp[2,0], Tmp[2,2]);
  419. M[1,1] := _DET(Tmp[0,0], Tmp[0,2], Tmp[2,0], Tmp[2,2]);
  420. M[1,2] := -_DET(Tmp[0,0], Tmp[0,2], Tmp[1,0], Tmp[1,2]);
  421. M[2,0] := _DET(Tmp[1,0], Tmp[1,1], Tmp[2,0], Tmp[2,1]);
  422. M[2,1] := -_DET(Tmp[0,0], Tmp[0,1], Tmp[2,0], Tmp[2,1]);
  423. M[2,2] := _DET(Tmp[0,0], Tmp[0,1], Tmp[1,0], Tmp[1,1]);
  424. end;
  425. function Determinant(const M: TFloatMatrix): TFloat;
  426. begin
  427. Result := _DET(M[0,0], M[1,0], M[2,0],
  428. M[0,1], M[1,1], M[2,1],
  429. M[0,2], M[1,2], M[2,2]);
  430. end;
  431. procedure Scale(var M: TFloatMatrix; Factor: TFloat);
  432. var
  433. i, j: Integer;
  434. begin
  435. for i := 0 to 2 do
  436. for j := 0 to 2 do
  437. M[i,j] := M[i,j] * Factor;
  438. end;
  439. procedure Invert(var M: TFloatMatrix);
  440. var
  441. Det: TFloat;
  442. begin
  443. Det := Determinant(M);
  444. if Abs(Det) < 1E-5 then
  445. M := IdentityMatrix
  446. else
  447. begin
  448. Adjoint(M);
  449. Scale(M, 1 / Det);
  450. end;
  451. end;
  452. function Mult(const M1, M2: TFloatMatrix): TFloatMatrix;
  453. var
  454. i, j: Integer;
  455. begin
  456. for i := 0 to 2 do
  457. for j := 0 to 2 do
  458. Result[i, j] :=
  459. M1[0, j] * M2[i, 0] +
  460. M1[1, j] * M2[i, 1] +
  461. M1[2, j] * M2[i, 2];
  462. end;
  463. function VectorTransform(const M: TFloatMatrix; const V: TVector3f): TVector3f;
  464. begin
  465. Result[0] := M[0,0] * V[0] + M[1,0] * V[1] + M[2,0] * V[2];
  466. Result[1] := M[0,1] * V[0] + M[1,1] * V[1] + M[2,1] * V[2];
  467. Result[2] := M[0,2] * V[0] + M[1,2] * V[1] + M[2,2] * V[2];
  468. end;
  469. { Transformation functions }
  470. function TransformPoints(Points: TArrayOfArrayOfFixedPoint; Transformation: TTransformation): TArrayOfArrayOfFixedPoint;
  471. var
  472. I, J: Integer;
  473. begin
  474. if Points = nil then
  475. Result := nil
  476. else
  477. begin
  478. SetLength(Result, Length(Points));
  479. Transformation.PrepareTransform;
  480. for I := 0 to High(Result) do
  481. begin
  482. SetLength(Result[I], Length(Points[I]));
  483. if Length(Result[I]) > 0 then
  484. for J := 0 to High(Result[I]) do
  485. Transformation.TransformFixed(Points[I][J].X, Points[I][J].Y, Result[I][J].X, Result[I][J].Y);
  486. end;
  487. end;
  488. end;
  489. procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation; Reverse: boolean);
  490. var
  491. Rasterizer: TRasterizer;
  492. begin
  493. Rasterizer := DefaultRasterizerClass.Create;
  494. try
  495. Transform(Dst, Src, Transformation, Rasterizer, Reverse);
  496. finally
  497. Rasterizer.Free;
  498. end;
  499. end;
  500. procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation; const DstClip: TRect; Reverse: boolean);
  501. var
  502. Rasterizer: TRasterizer;
  503. begin
  504. Rasterizer := DefaultRasterizerClass.Create;
  505. try
  506. Transform(Dst, Src, Transformation, Rasterizer, DstClip, Reverse);
  507. finally
  508. Rasterizer.Free;
  509. end;
  510. end;
  511. procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation;
  512. Rasterizer: TRasterizer; Reverse: boolean);
  513. begin
  514. Transform(Dst, Src, Transformation, Rasterizer, Dst.BoundsRect, Reverse);
  515. end;
  516. procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation;
  517. Rasterizer: TRasterizer; const DstClip: TRect; Reverse: boolean);
  518. var
  519. DstRect: TRect;
  520. Transformer: TTransformer;
  521. begin
  522. GR32.IntersectRect(DstRect, DstClip, Dst.ClipRect);
  523. if (DstRect.Right < DstRect.Left) or (DstRect.Bottom < DstRect.Top) then
  524. Exit;
  525. if not Dst.MeasuringMode then
  526. begin
  527. Transformer := TTransformer.Create(Src.Resampler, Transformation, Reverse);
  528. try
  529. Rasterizer.Sampler := Transformer;
  530. Rasterizer.Rasterize(Dst, DstRect, Src);
  531. finally
  532. EMMS;
  533. Transformer.Free;
  534. end;
  535. end;
  536. Dst.Changed(DstRect);
  537. end;
  538. procedure SetBorderTransparent(ABitmap: TCustomBitmap32; ARect: TRect);
  539. var
  540. I: Integer;
  541. begin
  542. GR32.IntersectRect(ARect, ARect, ABitmap.BoundsRect);
  543. with ARect, ABitmap do
  544. if (Right > Left) and (Bottom > Top) and
  545. (Left < ClipRect.Right) and (Top < ClipRect.Bottom) and
  546. (Right > ClipRect.Left) and (Bottom > ClipRect.Top) then
  547. begin
  548. Dec(Right);
  549. Dec(Bottom);
  550. for I := Left to Right do
  551. begin
  552. ABitmap[I, Top] := ABitmap[I, Top] and $00FFFFFF;
  553. ABitmap[I, Bottom] := ABitmap[I, Bottom] and $00FFFFFF;
  554. end;
  555. for I := Top to Bottom do
  556. begin
  557. ABitmap[Left, I] := ABitmap[Left, I] and $00FFFFFF;
  558. ABitmap[Right, I] := ABitmap[Right, I] and $00FFFFFF;
  559. end;
  560. Changed;
  561. end;
  562. end;
  563. { TTransformation }
  564. function TTransformation.GetTransformedBounds: TFloatRect;
  565. begin
  566. Result := GetTransformedBounds(FSrcRect);
  567. end;
  568. procedure TTransformation.Changed;
  569. begin
  570. TransformValid := False;
  571. inherited;
  572. end;
  573. constructor TTransformation.Create;
  574. begin
  575. // virtual constructor to be overriden in derived classes
  576. end;
  577. function TTransformation.GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect;
  578. begin
  579. Result := ASrcRect;
  580. end;
  581. function TTransformation.HasTransformedBounds: Boolean;
  582. begin
  583. Result := True;
  584. end;
  585. procedure TTransformation.PrepareTransform;
  586. begin
  587. // Dummy
  588. end;
  589. function TTransformation.ReverseTransform(const P: TFloatPoint): TFloatPoint;
  590. begin
  591. if not TransformValid then
  592. PrepareTransform;
  593. ReverseTransformFloat(P.X, P.Y, Result.X, Result.Y);
  594. end;
  595. function TTransformation.ReverseTransform(const P: TFixedPoint): TFixedPoint;
  596. begin
  597. if not TransformValid then
  598. PrepareTransform;
  599. ReverseTransformFixed(P.X, P.Y, Result.X, Result.Y);
  600. end;
  601. function TTransformation.ReverseTransform(const P: TPoint): TPoint;
  602. begin
  603. if not TransformValid then
  604. PrepareTransform;
  605. ReverseTransformInt(P.X, P.Y, Result.X, Result.Y);
  606. end;
  607. procedure TTransformation.ReverseTransformFixed(DstX, DstY: TFixed;
  608. out SrcX, SrcY: TFixed);
  609. var
  610. X, Y: TFloat;
  611. begin
  612. ReverseTransformFloat(DstX * FixedToFloat, DstY * FixedToFloat, X, Y);
  613. SrcX := Fixed(X);
  614. SrcY := Fixed(Y);
  615. end;
  616. procedure TTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
  617. out SrcX, SrcY: TFloat);
  618. begin
  619. // ReverseTransformFloat is the top precisionlevel, all descendants must override at least this level!
  620. raise ETransformNotImplemented.CreateFmt(RCStrReverseTransformationNotImplemented, [Self.Classname]);
  621. end;
  622. procedure TTransformation.ReverseTransformInt(DstX, DstY: Integer;
  623. out SrcX, SrcY: Integer);
  624. var
  625. X, Y: TFixed;
  626. begin
  627. ReverseTransformFixed(DstX shl 16, DstY shl 16, X, Y);
  628. SrcX := FixedRound(X);
  629. SrcY := FixedRound(Y);
  630. end;
  631. procedure TTransformation.SetSrcRect(const Value: TFloatRect);
  632. begin
  633. FSrcRect := Value;
  634. Changed;
  635. end;
  636. function TTransformation.Transform(const P: TFloatPoint): TFloatPoint;
  637. begin
  638. if not TransformValid then
  639. PrepareTransform;
  640. TransformFloat(P.X, P.Y, Result.X, Result.Y);
  641. end;
  642. function TTransformation.Transform(const P: TFixedPoint): TFixedPoint;
  643. begin
  644. if not TransformValid then
  645. PrepareTransform;
  646. TransformFixed(P.X, P.Y, Result.X, Result.Y);
  647. end;
  648. function TTransformation.Transform(const P: TPoint): TPoint;
  649. begin
  650. if not TransformValid then
  651. PrepareTransform;
  652. TransformInt(P.X, P.Y, Result.X, Result.Y);
  653. end;
  654. procedure TTransformation.TransformFixed(SrcX, SrcY: TFixed; out DstX,
  655. DstY: TFixed);
  656. var
  657. X, Y: TFloat;
  658. begin
  659. TransformFloat(SrcX * FixedToFloat, SrcY * FixedToFloat, X, Y);
  660. DstX := Fixed(X);
  661. DstY := Fixed(Y);
  662. end;
  663. procedure TTransformation.TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat);
  664. begin
  665. // TransformFloat is the top precisionlevel, all descendants must override at least this level!
  666. raise ETransformNotImplemented.CreateFmt(RCStrForwardTransformationNotImplemented, [Self.Classname]);
  667. end;
  668. procedure TTransformation.TransformInt(SrcX, SrcY: Integer; out DstX, DstY: Integer);
  669. var
  670. X, Y: TFixed;
  671. begin
  672. TransformFixed(SrcX shl 16, SrcY shl 16, X, Y);
  673. DstX := FixedRound(X);
  674. DstY := FixedRound(Y);
  675. end;
  676. { TNestedTransformation }
  677. constructor TNestedTransformation.Create;
  678. begin
  679. FItems := TList.Create;
  680. end;
  681. destructor TNestedTransformation.Destroy;
  682. begin
  683. if Assigned(FItems) then
  684. Clear;
  685. FItems.Free;
  686. inherited;
  687. end;
  688. function TNestedTransformation.Add(
  689. ItemClass: TTransformationClass): TTransformation;
  690. begin
  691. Result := ItemClass.Create;
  692. {$IFDEF NEXTGEN}
  693. Result.__ObjAddRef;
  694. {$ENDIF}
  695. FItems.Add(Result);
  696. end;
  697. procedure TNestedTransformation.Clear;
  698. begin
  699. BeginUpdate;
  700. try
  701. while FItems.Count > 0 do
  702. Delete(FItems.Count - 1);
  703. finally
  704. EndUpdate;
  705. end;
  706. end;
  707. procedure TNestedTransformation.Delete(Index: Integer);
  708. begin
  709. TTransformation(FItems[Index]).Free;
  710. FItems.Delete(Index);
  711. end;
  712. function TNestedTransformation.GetCount: Integer;
  713. begin
  714. Result := FItems.Count;
  715. end;
  716. function TNestedTransformation.GetItem(Index: Integer): TTransformation;
  717. begin
  718. Result := FItems[Index];
  719. end;
  720. function TNestedTransformation.Insert(Index: Integer;
  721. ItemClass: TTransformationClass): TTransformation;
  722. begin
  723. BeginUpdate;
  724. try
  725. Result := Add(ItemClass);
  726. finally
  727. EndUpdate;
  728. end;
  729. end;
  730. procedure TNestedTransformation.PrepareTransform;
  731. var
  732. Index: Integer;
  733. begin
  734. for Index := 0 to Count - 1 do
  735. TTransformation(FItems[Index]).PrepareTransform;
  736. end;
  737. procedure TNestedTransformation.ReverseTransformFixed(DstX, DstY: TFixed;
  738. out SrcX, SrcY: TFixed);
  739. var
  740. Index: Integer;
  741. begin
  742. for Index := 0 to Count - 1 do
  743. begin
  744. TTransformation(FItems[Index]).ReverseTransformFixed(DstX, DstY, SrcX,
  745. SrcY);
  746. DstX := SrcX;
  747. DstY := SrcY;
  748. end;
  749. end;
  750. procedure TNestedTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
  751. out SrcX, SrcY: TFloat);
  752. var
  753. Index: Integer;
  754. begin
  755. for Index := 0 to Count - 1 do
  756. begin
  757. TTransformation(FItems[Index]).ReverseTransformFloat(DstX, DstY, SrcX,
  758. SrcY);
  759. DstX := SrcX;
  760. DstY := SrcY;
  761. end;
  762. end;
  763. procedure TNestedTransformation.SetItem(Index: Integer;
  764. const Value: TTransformation);
  765. begin
  766. TCollectionItem(FItems[Index]).Assign(Value);
  767. end;
  768. procedure TNestedTransformation.TransformFixed(SrcX, SrcY: TFixed; out DstX,
  769. DstY: TFixed);
  770. var
  771. Index: Integer;
  772. begin
  773. for Index := 0 to Count - 1 do
  774. begin
  775. TTransformation(FItems[Index]).TransformFixed(SrcX, SrcY, DstX, DstY);
  776. SrcX := DstX;
  777. SrcY := DstY;
  778. end;
  779. end;
  780. procedure TNestedTransformation.TransformFloat(SrcX, SrcY: TFloat; out DstX,
  781. DstY: TFloat);
  782. var
  783. Index: Integer;
  784. begin
  785. for Index := 0 to Count - 1 do
  786. begin
  787. TTransformation(FItems[Index]).TransformFloat(SrcX, SrcY, DstX, DstY);
  788. SrcX := DstX;
  789. SrcY := DstY;
  790. end;
  791. end;
  792. { T3x3Transformation }
  793. procedure T3x3Transformation.PrepareTransform;
  794. begin
  795. FInverseMatrix := Matrix;
  796. Invert(FInverseMatrix);
  797. // calculate a fixed point (65536) factors
  798. FInverseFixedMatrix := FixedMatrix(FInverseMatrix);
  799. FFixedMatrix := FixedMatrix(Matrix);
  800. TransformValid := True;
  801. end;
  802. procedure T3x3Transformation.ReverseTransformFixed(DstX, DstY: TFixed; out SrcX,
  803. SrcY: TFixed);
  804. begin
  805. SrcX := FixedMul(DstX, FInverseFixedMatrix[0, 0]) +
  806. FixedMul(DstY, FInverseFixedMatrix[1, 0]) + FInverseFixedMatrix[2, 0];
  807. SrcY := FixedMul(DstX, FInverseFixedMatrix[0, 1]) +
  808. FixedMul(DstY, FInverseFixedMatrix[1, 1]) + FInverseFixedMatrix[2, 1];
  809. end;
  810. procedure T3x3Transformation.ReverseTransformFloat(DstX, DstY: TFloat; out SrcX,
  811. SrcY: TFloat);
  812. begin
  813. SrcX := DstX * FInverseMatrix[0, 0] + DstY * FInverseMatrix[1, 0] +
  814. FInverseMatrix[2, 0];
  815. SrcY := DstX * FInverseMatrix[0, 1] + DstY * FInverseMatrix[1, 1] +
  816. FInverseMatrix[2, 1];
  817. end;
  818. procedure T3x3Transformation.TransformFixed(SrcX, SrcY: TFixed; out DstX,
  819. DstY: TFixed);
  820. begin
  821. DstX := FixedMul(SrcX, FFixedMatrix[0, 0]) +
  822. FixedMul(SrcY, FFixedMatrix[1, 0]) + FFixedMatrix[2, 0];
  823. DstY := FixedMul(SrcX, FFixedMatrix[0, 1]) +
  824. FixedMul(SrcY, FFixedMatrix[1, 1]) + FFixedMatrix[2, 1];
  825. end;
  826. procedure T3x3Transformation.TransformFloat(SrcX, SrcY: TFloat; out DstX,
  827. DstY: TFloat);
  828. begin
  829. DstX := SrcX * Matrix[0, 0] + SrcY * Matrix[1, 0] + Matrix[2, 0];
  830. DstY := SrcX * Matrix[0, 1] + SrcY * Matrix[1, 1] + Matrix[2, 1];
  831. end;
  832. { TAffineTransformation }
  833. constructor TAffineTransformation.Create;
  834. begin
  835. FStackLevel := 0;
  836. FStack := nil;
  837. Clear;
  838. end;
  839. procedure TAffineTransformation.Clear;
  840. begin
  841. FMatrix := IdentityMatrix;
  842. Changed;
  843. end;
  844. procedure TAffineTransformation.Clear(BaseMatrix: TFloatMatrix);
  845. begin
  846. FMatrix := BaseMatrix;
  847. Changed;
  848. end;
  849. function TAffineTransformation.GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect;
  850. var
  851. V1, V2, V3, V4: TVector3f;
  852. begin
  853. V1[0] := ASrcRect.Left; V1[1] := ASrcRect.Top; V1[2] := 1;
  854. V2[0] := ASrcRect.Right; V2[1] := V1[1]; V2[2] := 1;
  855. V3[0] := V1[0]; V3[1] := ASrcRect.Bottom; V3[2] := 1;
  856. V4[0] := V2[0]; V4[1] := V3[1]; V4[2] := 1;
  857. V1 := VectorTransform(Matrix, V1);
  858. V2 := VectorTransform(Matrix, V2);
  859. V3 := VectorTransform(Matrix, V3);
  860. V4 := VectorTransform(Matrix, V4);
  861. Result.Left := Min(Min(V1[0], V2[0]), Min(V3[0], V4[0]));
  862. Result.Right := Max(Max(V1[0], V2[0]), Max(V3[0], V4[0]));
  863. Result.Top := Min(Min(V1[1], V2[1]), Min(V3[1], V4[1]));
  864. Result.Bottom := Max(Max(V1[1], V2[1]), Max(V3[1], V4[1]));
  865. end;
  866. procedure TAffineTransformation.Push;
  867. begin
  868. Inc(FStackLevel);
  869. ReallocMem(FStack, FStackLevel * SizeOf(TFloatMatrix));
  870. Move(FMatrix, FStack^[FStackLevel - 1], SizeOf(TFloatMatrix));
  871. end;
  872. procedure TAffineTransformation.Pop;
  873. begin
  874. if FStackLevel <= 0 then
  875. raise Exception.Create(RStrStackEmpty);
  876. Move(FStack^[FStackLevel - 1], FMatrix, SizeOf(TFloatMatrix));
  877. Dec(FStackLevel);
  878. Changed;
  879. end;
  880. procedure TAffineTransformation.Rotate(Alpha: TFloat);
  881. var
  882. S, C: TFloat;
  883. M: TFloatMatrix;
  884. begin
  885. Alpha := DegToRad(Alpha);
  886. GR32_Math.SinCos(Alpha, S, C);
  887. M := IdentityMatrix;
  888. M[0, 0] := C; M[1, 0] := S;
  889. M[0, 1] := -S; M[1, 1] := C;
  890. FMatrix := Mult(M, Matrix);
  891. Changed;
  892. end;
  893. procedure TAffineTransformation.Rotate(Cx, Cy, Alpha: TFloat);
  894. var
  895. S, C: TFloat;
  896. M: TFloatMatrix;
  897. begin
  898. if (Cx <> 0) or (Cy <> 0) then
  899. Translate(-Cx, -Cy);
  900. Alpha := DegToRad(Alpha);
  901. GR32_Math.SinCos(Alpha, S, C);
  902. M := IdentityMatrix;
  903. M[0, 0] := C; M[1, 0] := S;
  904. M[0, 1] := -S; M[1, 1] := C;
  905. FMatrix := Mult(M, Matrix);
  906. if (Cx <> 0) or (Cy <> 0) then
  907. Translate(Cx, Cy);
  908. Changed;
  909. end;
  910. procedure TAffineTransformation.Scale(Sx, Sy: TFloat);
  911. var
  912. M: TFloatMatrix;
  913. begin
  914. M := IdentityMatrix;
  915. M[0, 0] := Sx;
  916. M[1, 1] := Sy;
  917. FMatrix := Mult(M, Matrix);
  918. Changed;
  919. end;
  920. procedure TAffineTransformation.Scale(Value: TFloat);
  921. var
  922. M: TFloatMatrix;
  923. begin
  924. M := IdentityMatrix;
  925. M[0, 0] := Value;
  926. M[1, 1] := Value;
  927. FMatrix := Mult(M, Matrix);
  928. Changed;
  929. end;
  930. procedure TAffineTransformation.Skew(Fx, Fy: TFloat);
  931. var
  932. M: TFloatMatrix;
  933. begin
  934. M := IdentityMatrix;
  935. M[1, 0] := Fx;
  936. M[0, 1] := Fy;
  937. FMatrix := Mult(M, Matrix);
  938. Changed;
  939. end;
  940. procedure TAffineTransformation.Translate(Dx, Dy: TFloat);
  941. var
  942. M: TFloatMatrix;
  943. begin
  944. M := IdentityMatrix;
  945. M[2, 0] := Dx;
  946. M[2, 1] := Dy;
  947. FMatrix := Mult(M, Matrix);
  948. Changed;
  949. end;
  950. { TProjectiveTransformation }
  951. function TProjectiveTransformation.GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect;
  952. begin
  953. Result.Left := Min(Min(FQuadX[0], FQuadX[1]), Min(FQuadX[2], FQuadX[3]));
  954. Result.Right := Max(Max(FQuadX[0], FQuadX[1]), Max(FQuadX[2], FQuadX[3]));
  955. Result.Top := Min(Min(FQuadY[0], FQuadY[1]), Min(FQuadY[2], FQuadY[3]));
  956. Result.Bottom := Max(Max(FQuadY[0], FQuadY[1]), Max(FQuadY[2], FQuadY[3]));
  957. end;
  958. function TProjectiveTransformation.GetX(Index: Integer): TFloat;
  959. begin
  960. Result := FQuadX[Index];
  961. end;
  962. function TProjectiveTransformation.GetY(Index: Integer): TFloat;
  963. begin
  964. Result := FQuadY[Index];
  965. end;
  966. procedure TProjectiveTransformation.PrepareTransform;
  967. var
  968. dx1, dx2, px, dy1, dy2, py: TFloat;
  969. g, h, k: TFloat;
  970. R: TFloatMatrix;
  971. begin
  972. px := FQuadX[0] - FQuadX[1] + FQuadX[2] - FQuadX[3];
  973. py := FQuadY[0] - FQuadY[1] + FQuadY[2] - FQuadY[3];
  974. if (px = 0) and (py = 0) then
  975. begin
  976. // affine mapping
  977. FMatrix[0, 0] := FQuadX[1] - FQuadX[0];
  978. FMatrix[1, 0] := FQuadX[2] - FQuadX[1];
  979. FMatrix[2, 0] := FQuadX[0];
  980. FMatrix[0, 1] := FQuadY[1] - FQuadY[0];
  981. FMatrix[1, 1] := FQuadY[2] - FQuadY[1];
  982. FMatrix[2, 1] := FQuadY[0];
  983. FMatrix[0, 2] := 0;
  984. FMatrix[1, 2] := 0;
  985. FMatrix[2, 2] := 1;
  986. end
  987. else
  988. begin
  989. // projective mapping
  990. dx1 := FQuadX[1] - FQuadX[2];
  991. dx2 := FQuadX[3] - FQuadX[2];
  992. dy1 := FQuadY[1] - FQuadY[2];
  993. dy2 := FQuadY[3] - FQuadY[2];
  994. k := dx1 * dy2 - dx2 * dy1;
  995. if k <> 0 then
  996. begin
  997. k := 1 / k;
  998. g := (px * dy2 - py * dx2) * k;
  999. h := (dx1 * py - dy1 * px) * k;
  1000. FMatrix[0, 0] := FQuadX[1] - FQuadX[0] + g * FQuadX[1];
  1001. FMatrix[1, 0] := FQuadX[3] - FQuadX[0] + h * FQuadX[3];
  1002. FMatrix[2, 0] := FQuadX[0];
  1003. FMatrix[0, 1] := FQuadY[1] - FQuadY[0] + g * FQuadY[1];
  1004. FMatrix[1, 1] := FQuadY[3] - FQuadY[0] + h * FQuadY[3];
  1005. FMatrix[2, 1] := FQuadY[0];
  1006. FMatrix[0, 2] := g;
  1007. FMatrix[1, 2] := h;
  1008. FMatrix[2, 2] := 1;
  1009. end
  1010. else
  1011. begin
  1012. FillChar(FMatrix, SizeOf(FMatrix), 0);
  1013. end;
  1014. end;
  1015. // denormalize texture space (u, v)
  1016. R := IdentityMatrix;
  1017. R[0, 0] := 1 / (SrcRect.Right - SrcRect.Left);
  1018. R[1, 1] := 1 / (SrcRect.Bottom - SrcRect.Top);
  1019. FMatrix := Mult(FMatrix, R);
  1020. R := IdentityMatrix;
  1021. R[2, 0] := -SrcRect.Left;
  1022. R[2, 1] := -SrcRect.Top;
  1023. FMatrix := Mult(FMatrix, R);
  1024. inherited;
  1025. end;
  1026. procedure TProjectiveTransformation.SetX(Index: Integer; const Value: TFloat);
  1027. begin
  1028. FQuadX[Index] := Value;
  1029. Changed;
  1030. end;
  1031. procedure TProjectiveTransformation.SetY(Index: Integer; const Value: TFloat);
  1032. begin
  1033. FQuadY[Index] := Value;
  1034. Changed;
  1035. end;
  1036. procedure TProjectiveTransformation.ReverseTransformFixed(DstX, DstY: TFixed;
  1037. out SrcX, SrcY: TFixed);
  1038. var
  1039. Z: TFixed;
  1040. Zf: TFloat;
  1041. begin
  1042. Z := FixedMul(FInverseFixedMatrix[0, 2], DstX) +
  1043. FixedMul(FInverseFixedMatrix[1, 2], DstY) + FInverseFixedMatrix[2, 2];
  1044. if Z = 0 then
  1045. Exit;
  1046. {$IFDEF UseInlining}
  1047. SrcX := FixedMul(DstX, FInverseFixedMatrix[0, 0]) +
  1048. FixedMul(DstY, FInverseFixedMatrix[1, 0]) + FInverseFixedMatrix[2, 0];
  1049. SrcY := FixedMul(DstX, FInverseFixedMatrix[0,1]) +
  1050. FixedMul(DstY, FInverseFixedMatrix[1, 1]) + FInverseFixedMatrix[2, 1];
  1051. {$ELSE}
  1052. inherited;
  1053. {$ENDIF}
  1054. if Z <> FixedOne then
  1055. begin
  1056. EMMS;
  1057. Zf := FixedOne / Z;
  1058. SrcX := Round(SrcX * Zf);
  1059. SrcY := Round(SrcY * Zf);
  1060. end;
  1061. end;
  1062. procedure TProjectiveTransformation.ReverseTransformFloat(
  1063. DstX, DstY: TFloat;
  1064. out SrcX, SrcY: TFloat);
  1065. var
  1066. Z: TFloat;
  1067. begin
  1068. EMMS;
  1069. Z := FInverseMatrix[0, 2] * DstX + FInverseMatrix[1, 2] * DstY +
  1070. FInverseMatrix[2, 2];
  1071. if Z = 0 then
  1072. Exit;
  1073. {$IFDEF UseInlining}
  1074. SrcX := DstX * FInverseMatrix[0, 0] + DstY * FInverseMatrix[1, 0] +
  1075. FInverseMatrix[2, 0];
  1076. SrcY := DstX * FInverseMatrix[0, 1] + DstY * FInverseMatrix[1, 1] +
  1077. FInverseMatrix[2, 1];
  1078. {$ELSE}
  1079. inherited;
  1080. {$ENDIF}
  1081. if Z <> 1 then
  1082. begin
  1083. Z := 1 / Z;
  1084. SrcX := SrcX * Z;
  1085. SrcY := SrcY * Z;
  1086. end;
  1087. end;
  1088. procedure TProjectiveTransformation.TransformFixed(SrcX, SrcY: TFixed;
  1089. out DstX, DstY: TFixed);
  1090. var
  1091. Z: TFixed;
  1092. Zf: TFloat;
  1093. begin
  1094. Z := FixedMul(FFixedMatrix[0, 2], SrcX) +
  1095. FixedMul(FFixedMatrix[1, 2], SrcY) + FFixedMatrix[2, 2];
  1096. if Z = 0 then
  1097. Exit;
  1098. {$IFDEF UseInlining}
  1099. DstX := FixedMul(SrcX, FFixedMatrix[0, 0]) +
  1100. FixedMul(SrcY, FFixedMatrix[1, 0]) + FFixedMatrix[2, 0];
  1101. DstY := FixedMul(SrcX, FFixedMatrix[0, 1]) +
  1102. FixedMul(SrcY, FFixedMatrix[1, 1]) + FFixedMatrix[2, 1];
  1103. {$ELSE}
  1104. inherited;
  1105. {$ENDIF}
  1106. if Z <> FixedOne then
  1107. begin
  1108. EMMS;
  1109. Zf := FixedOne / Z;
  1110. DstX := Round(DstX * Zf);
  1111. DstY := Round(DstY * Zf);
  1112. end;
  1113. end;
  1114. procedure TProjectiveTransformation.TransformFloat(SrcX, SrcY: TFloat;
  1115. out DstX, DstY: TFloat);
  1116. var
  1117. Z: TFloat;
  1118. begin
  1119. EMMS;
  1120. Z := FMatrix[0, 2] * SrcX + FMatrix[1, 2] * SrcY + FMatrix[2, 2];
  1121. if Z = 0 then Exit;
  1122. {$IFDEF UseInlining}
  1123. DstX := SrcX * Matrix[0, 0] + SrcY * Matrix[1, 0] + Matrix[2, 0];
  1124. DstY := SrcX * Matrix[0, 1] + SrcY * Matrix[1, 1] + Matrix[2, 1];
  1125. {$ELSE}
  1126. inherited;
  1127. {$ENDIF}
  1128. if Z <> 1 then
  1129. begin
  1130. Z := 1 / Z;
  1131. DstX := DstX * Z;
  1132. DstY := DstY * Z;
  1133. end;
  1134. end;
  1135. { TTwirlTransformation }
  1136. constructor TTwirlTransformation.Create;
  1137. begin
  1138. FTwirl := 0.03;
  1139. end;
  1140. function TTwirlTransformation.GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect;
  1141. var
  1142. Cx, Cy, R: TFloat;
  1143. const
  1144. CPiHalf: TFloat = 0.5 * Pi;
  1145. begin
  1146. Cx := (ASrcRect.Left + ASrcRect.Right) * 0.5;
  1147. Cy := (ASrcRect.Top + ASrcRect.Bottom) * 0.5;
  1148. R := Max(Cx - ASrcRect.Left, Cy - ASrcRect.Top);
  1149. Result.Left := Cx - R * CPiHalf;
  1150. Result.Right := Cx + R * CPiHalf;
  1151. Result.Top := Cy - R * CPiHalf;
  1152. Result.Bottom := Cy + R * CPiHalf;
  1153. end;
  1154. procedure TTwirlTransformation.PrepareTransform;
  1155. begin
  1156. with FSrcRect do
  1157. begin
  1158. Frx := (Right - Left) * 0.5;
  1159. Fry := (Bottom - Top) * 0.5;
  1160. end;
  1161. TransformValid := True;
  1162. end;
  1163. procedure TTwirlTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
  1164. out SrcX, SrcY: TFloat);
  1165. var
  1166. xf, yf, r, t: Single;
  1167. begin
  1168. xf := DstX - Frx;
  1169. yf := DstY - Fry;
  1170. r := GR32_Math.Hypot(xf, yf);
  1171. t := ArcTan2(yf, xf) + r * FTwirl;
  1172. GR32_Math.SinCos(t, yf, xf);
  1173. SrcX := Frx + r * xf;
  1174. SrcY := Fry + r * yf;
  1175. end;
  1176. procedure TTwirlTransformation.SetTwirl(const Value: TFloat);
  1177. begin
  1178. FTwirl := Value;
  1179. Changed;
  1180. end;
  1181. { TBloatTransformation }
  1182. constructor TBloatTransformation.Create;
  1183. begin
  1184. FBloatPower := 0.3;
  1185. end;
  1186. procedure TBloatTransformation.PrepareTransform;
  1187. begin
  1188. FPiW := (Pi / (FSrcRect.Right - FSrcRect.Left));
  1189. FPiH := (Pi / (FSrcRect.Bottom - FSrcRect.Top));
  1190. FBP := FBloatPower * Max(FSrcRect.Right - FSrcRect.Left, FSrcRect.Bottom - FSrcRect.Top);
  1191. TransformValid := True;
  1192. end;
  1193. procedure TBloatTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
  1194. out SrcX, SrcY: TFloat);
  1195. var
  1196. SinY, CosY, SinX, CosX, t: Single;
  1197. begin
  1198. GR32_Math.SinCos(FPiH * DstY, SinY, CosY);
  1199. GR32_Math.SinCos(FPiW * DstX, SinX, CosX);
  1200. t := FBP * SinY * SinX;
  1201. SrcX := DstX + t * CosX;
  1202. SrcY := DstY + t * CosY;
  1203. end;
  1204. procedure TBloatTransformation.TransformFloat(DstX, DstY: TFloat;
  1205. out SrcX, SrcY: TFloat);
  1206. var
  1207. SinY, CosY, SinX, CosX, t: Single;
  1208. begin
  1209. GR32_Math.SinCos(-FPiH * DstY, SinY, CosY);
  1210. GR32_Math.SinCos(-FPiW * DstX, SinX, CosX);
  1211. t := FBP * SinY * SinX;
  1212. SrcX := DstX + t * CosX;
  1213. SrcY := DstY + t * CosY;
  1214. end;
  1215. procedure TBloatTransformation.SetBloatPower(const Value: TFloat);
  1216. begin
  1217. FBloatPower := Value;
  1218. Changed;
  1219. end;
  1220. { TFishEyeTransformation }
  1221. procedure TFishEyeTransformation.PrepareTransform;
  1222. begin
  1223. with FSrcRect do
  1224. begin
  1225. Frx := (Right - Left) * 0.5;
  1226. Fry := (Bottom - Top) * 0.5;
  1227. if Frx <= Fry then
  1228. begin
  1229. FMinR := Frx;
  1230. Sx := 1;
  1231. Sy:= Frx / Fry;
  1232. end
  1233. else
  1234. begin
  1235. FMinR := Fry;
  1236. Sx:= Fry / Frx;
  1237. Sy := 1;
  1238. end;
  1239. Fsr := 1 / FMinR;
  1240. Faw := ArcSin(Constrain(FMinR * Fsr, -1, 1));
  1241. if Faw <> 0 then
  1242. Faw := 1 / Faw;
  1243. Faw := Faw * FMinR
  1244. end;
  1245. TransformValid := True;
  1246. end;
  1247. procedure TFishEyeTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
  1248. out SrcX, SrcY: TFloat);
  1249. var
  1250. d, Xrx, Yry: TFloat;
  1251. begin
  1252. Yry := (DstY - Fry) * sy;
  1253. Xrx := (DstX - Frx) * sx;
  1254. d := GR32_Math.Hypot(Xrx, Yry);
  1255. if (d < FMinR) and (d > 0) then
  1256. begin
  1257. d := ArcSin(d * Fsr) * Faw / d;
  1258. SrcX := Frx + Xrx * d;
  1259. SrcY := Fry + Yry * d;
  1260. end
  1261. else
  1262. begin
  1263. SrcX := DstX;
  1264. SrcY := DstY;
  1265. end;
  1266. end;
  1267. { TPolarTransformation }
  1268. procedure TPolarTransformation.PrepareTransform;
  1269. begin
  1270. Sx := SrcRect.Right - SrcRect.Left;
  1271. Sy := SrcRect.Bottom - SrcRect.Top;
  1272. Cx := (DstRect.Left + DstRect.Right) * 0.5;
  1273. Cy := (DstRect.Top + DstRect.Bottom) * 0.5;
  1274. Dx := DstRect.Right - Cx;
  1275. Dy := DstRect.Bottom - Cy;
  1276. Rt := (1 / (PI * 2)) * Sx;
  1277. Rt2 := Sx;
  1278. if Rt2 <> 0 then
  1279. Rt2 := 1 / Sx
  1280. else
  1281. Rt2 := 0.00000001;
  1282. Rt2 := Rt2 * 2 * Pi;
  1283. Rr := Sy;
  1284. if Rr <> 0 then
  1285. Rr := 1 / Rr
  1286. else
  1287. Rr := 0.00000001;
  1288. Rcx := Cx;
  1289. if Rcx <> 0 then
  1290. Rcx := 1 / Rcx
  1291. else
  1292. Rcx := 0.00000001;
  1293. Rcy := Cy;
  1294. if Rcy <> 0 then
  1295. Rcy := 1 / Rcy
  1296. else
  1297. Rcy := 0.00000001;
  1298. TransformValid := True;
  1299. end;
  1300. procedure TPolarTransformation.SetDstRect(const Value: TFloatRect);
  1301. begin
  1302. FDstRect := Value;
  1303. Changed;
  1304. end;
  1305. procedure TPolarTransformation.TransformFloat(SrcX, SrcY: TFloat; out DstX,
  1306. DstY: TFloat);
  1307. var
  1308. R, Theta, S, C: TFloat;
  1309. begin
  1310. Theta := (SrcX - SrcRect.Left) * Rt2 + Phase;
  1311. R := (SrcY - SrcRect.Bottom) * Rr;
  1312. GR32_Math.SinCos(Theta, S, C);
  1313. DstX := Dx * R * C + Cx;
  1314. DstY := Dy * R * S + Cy;
  1315. end;
  1316. procedure TPolarTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
  1317. out SrcX, SrcY: TFloat);
  1318. const
  1319. PI2 = 2 * PI;
  1320. var
  1321. Dcx, Dcy, Theta: TFloat;
  1322. begin
  1323. Dcx := (DstX - Cx) * Rcx;
  1324. Dcy := (DstY - Cy) * Rcy;
  1325. Theta := ArcTan2(Dcy, Dcx) + Pi - Phase;
  1326. if Theta < 0 then
  1327. Theta := Theta + PI2;
  1328. SrcX := SrcRect.Left + Theta * Rt;
  1329. SrcY := SrcRect.Bottom - GR32_Math.Hypot(Dcx, Dcy) * Sy;
  1330. end;
  1331. procedure TPolarTransformation.SetPhase(const Value: TFloat);
  1332. begin
  1333. FPhase := Value;
  1334. Changed;
  1335. end;
  1336. { TPathTransformation }
  1337. destructor TPathTransformation.Destroy;
  1338. begin
  1339. FTopHypot := nil;
  1340. FBottomHypot := nil;
  1341. inherited;
  1342. end;
  1343. procedure TPathTransformation.PrepareTransform;
  1344. var
  1345. I: Integer;
  1346. L, DDist: TFloat;
  1347. begin
  1348. if not (Assigned(FTopCurve) and Assigned(FBottomCurve)) then
  1349. raise ETransformError.Create(RCStrTopBottomCurveNil);
  1350. SetLength(FTopHypot, Length(FTopCurve));
  1351. SetLength(FBottomHypot, Length(FBottomCurve));
  1352. L := 0;
  1353. for I := 0 to High(FTopCurve) - 1 do
  1354. begin
  1355. FTopHypot[I].Dist := L;
  1356. with FTopCurve[I + 1] do
  1357. L := L + GR32_Math.Hypot(FTopCurve[I].X - X, FTopCurve[I].Y - Y);
  1358. end;
  1359. FTopLength := L;
  1360. for I := 1 to High(FTopCurve) do
  1361. with FTopHypot[I] do
  1362. begin
  1363. DDist := Dist - FTopHypot[I - 1].Dist;
  1364. if DDist <> 0 then
  1365. RecDist := 1 / DDist
  1366. else
  1367. if I > 1 then
  1368. RecDist := FTopHypot[I - 1].RecDist
  1369. else
  1370. RecDist := 0;
  1371. end;
  1372. L := 0;
  1373. for I := 0 to High(FBottomCurve) - 1 do
  1374. begin
  1375. FBottomHypot[I].Dist := L;
  1376. with FBottomCurve[I + 1] do
  1377. L := L + GR32_Math.Hypot(FBottomCurve[I].X - X, FBottomCurve[I].Y - Y);
  1378. end;
  1379. FBottomLength := L;
  1380. for I := 1 to High(FBottomCurve) do
  1381. with FBottomHypot[I] do
  1382. begin
  1383. DDist := Dist - FBottomHypot[I - 1].Dist;
  1384. if DDist <> 0 then
  1385. RecDist := 1 / DDist
  1386. else
  1387. if I > 1 then
  1388. RecDist := FBottomHypot[I - 1].RecDist
  1389. else
  1390. RecDist := 0;
  1391. end;
  1392. rdx := 1 / (SrcRect.Right - SrcRect.Left);
  1393. rdy := 1 / (SrcRect.Bottom - SrcRect.Top);
  1394. TransformValid := True;
  1395. end;
  1396. procedure TPathTransformation.SetBottomCurve(const Value: TArrayOfFloatPoint);
  1397. begin
  1398. FBottomCurve := Value;
  1399. Changed;
  1400. end;
  1401. procedure TPathTransformation.SetTopCurve(const Value: TArrayOfFloatPoint);
  1402. begin
  1403. FTopCurve := Value;
  1404. Changed;
  1405. end;
  1406. procedure TPathTransformation.TransformFloat(SrcX, SrcY: TFloat; out DstX,
  1407. DstY: TFloat);
  1408. var
  1409. I, H: Integer;
  1410. X, Y, fx, dx, dy, r, Tx, Ty, Bx, By: TFloat;
  1411. begin
  1412. X := (SrcX - SrcRect.Left) * rdx;
  1413. Y := (SrcY - SrcRect.Top) * rdy;
  1414. fx := X * FTopLength;
  1415. I := 1;
  1416. H := High(FTopHypot);
  1417. while (FTopHypot[I].Dist < fx) and (I < H) do
  1418. Inc(I);
  1419. with FTopHypot[I] do
  1420. r := (Dist - fx) * RecDist;
  1421. dx := (FTopCurve[I - 1].X - FTopCurve[I].X);
  1422. dy := (FTopCurve[I - 1].Y - FTopCurve[I].Y);
  1423. Tx := FTopCurve[I].X + r * dx;
  1424. Ty := FTopCurve[I].Y + r * dy;
  1425. fx := X * FBottomLength;
  1426. I := 1;
  1427. H := High(FBottomHypot);
  1428. while (FBottomHypot[I].Dist < fx) and (I < H) do
  1429. Inc(I);
  1430. with FBottomHypot[I] do
  1431. r := (Dist - fx) * RecDist;
  1432. dx := (FBottomCurve[I - 1].X - FBottomCurve[I].X);
  1433. dy := (FBottomCurve[I - 1].Y - FBottomCurve[I].Y);
  1434. Bx := FBottomCurve[I].X + r * dx;
  1435. By := FBottomCurve[I].Y + r * dy;
  1436. DstX := Tx + Y * (Bx - Tx);
  1437. DstY := Ty + Y * (By - Ty);
  1438. end;
  1439. { TDisturbanceTransformation }
  1440. function TDisturbanceTransformation.GetTransformedBounds(
  1441. const ASrcRect: TFloatRect): TFloatRect;
  1442. begin
  1443. Result := ASrcRect;
  1444. InflateRect(Result, 0.5 * FDisturbance, 0.5 * FDisturbance);
  1445. end;
  1446. procedure TDisturbanceTransformation.ReverseTransformFloat(DstX,
  1447. DstY: TFloat; out SrcX, SrcY: TFloat);
  1448. begin
  1449. SrcX := DstX + (Random - 0.5) * FDisturbance;
  1450. SrcY := DstY + (Random - 0.5) * FDisturbance;
  1451. end;
  1452. procedure TDisturbanceTransformation.SetDisturbance(const Value: TFloat);
  1453. begin
  1454. FDisturbance := Value;
  1455. Changed;
  1456. end;
  1457. constructor TRadialDistortionTransformation.Create;
  1458. begin
  1459. FCoefficient1 := 0;
  1460. FCoefficient2 := 0;
  1461. FScale := 1;
  1462. FMapElements := 0;
  1463. end;
  1464. function TRadialDistortionTransformation.HasTransformedBounds: Boolean;
  1465. begin
  1466. Result := False;
  1467. end;
  1468. procedure TRadialDistortionTransformation.PrepareReverseMap;
  1469. var
  1470. i, j, LowerI, UpperI, jmax: Integer;
  1471. r_src, r_tgt, LowerValue, UpperValue: TFloat;
  1472. {$IFDEF DEBUG}
  1473. // some counters to evaluate the mapping
  1474. interpolated, unset, mapToSameIndex, IndexOutOfRange: Integer;
  1475. {$ENDIF}
  1476. begin
  1477. if MapElements <= 1 then
  1478. MapElements := Trunc(r_0);
  1479. r_tgt_max := 2;
  1480. r_tgt_min := -0.5;
  1481. SetLength(Map, MapElements);
  1482. for i := 0 to High(Map) do
  1483. Map[i] := -1;
  1484. jmax := 1000;
  1485. {$IFDEF DEBUG}
  1486. mapToSameIndex := 0;
  1487. IndexOutOfRange := 0;
  1488. {$ENDIF}
  1489. for j := 0 to jmax do
  1490. begin
  1491. r_src := j/jmax*2;
  1492. r_tgt := Scale*(1 + FCoefficient1 * Sqr(r_src) + FCoefficient2 * Power(r_src, 4));
  1493. Assert(InRange(r_tgt, r_tgt_min, r_tgt_max));
  1494. i := Trunc((r_tgt*r_src-r_tgt_min)/(r_tgt_max-r_tgt_min)*(High(Map)-1));
  1495. if not InRange(i, 0, High(Map)) then
  1496. begin
  1497. {$IFDEF DEBUG}
  1498. Inc(IndexOutOfRange);
  1499. // OutputDebugString(PChar(Format('PrepareReverseMap: i=%d out of range (0, MapElements=%d), r_tgt=%f', [ i, MapElements, r_tgt ])))
  1500. {$ENDIF}
  1501. end
  1502. else
  1503. if Map[i]<>-1 then
  1504. begin
  1505. {$IFDEF DEBUG}
  1506. Inc(mapToSameIndex);
  1507. // OutputDebugString(PChar(Format('PrepareReverseMap: Map[i=%d] already has value %f (wanted to put %f there)', [ i, Map[i], r_tgt ])))
  1508. {$ENDIF}
  1509. end
  1510. else
  1511. Map[i] := r_tgt;
  1512. end;
  1513. {$IFDEF DEBUG}
  1514. unset := 0;
  1515. for i := 0 to High(Map) do
  1516. begin
  1517. if Map[i] = -1 then
  1518. Inc(unset);
  1519. end;
  1520. {$ENDIF}
  1521. // linear interpolation where Map[i] == -1 (but no extrapolation)
  1522. i := 0;
  1523. LowerI := -1;
  1524. LowerValue := -1;
  1525. {$IFDEF DEBUG}
  1526. interpolated := 0;
  1527. {$ENDIF}
  1528. repeat
  1529. if Map[i] = -1 then
  1530. begin
  1531. if LowerI <> -1 then
  1532. begin
  1533. UpperI := i+1;
  1534. while (UpperI<=High(Map)) and (Map[UpperI] = -1) do
  1535. Inc(UpperI);
  1536. if UpperI<=High(Map) then
  1537. begin
  1538. UpperValue := Map[UpperI];
  1539. for j := LowerI+1 to UpperI-1 do
  1540. begin
  1541. Map[j] := LowerValue + (UpperValue-LowerValue) * (j-LowerI) / (UpperI - LowerI);
  1542. {$IFDEF DEBUG}
  1543. Inc(interpolated);
  1544. {$ENDIF}
  1545. end;
  1546. end;
  1547. end;
  1548. end
  1549. else
  1550. begin
  1551. LowerI := i;
  1552. LowerValue := Map[i];
  1553. end;
  1554. Inc(i);
  1555. until i > High(Map);
  1556. {$IFDEF DEBUG}
  1557. OutputDebugString(PChar(Format(
  1558. 'TRadialDistortionTransformation.PrepareReverseMap: mapToSameIndex=%d. IndexOutOfRange=%d. %d out of %d map elements were uninitialized, %d of these were interpolated',
  1559. [ mapToSameIndex, IndexOutOfRange, unset, High(Map), interpolated ])));
  1560. {$ENDIF}
  1561. for i := 0 to High(Map) do
  1562. begin
  1563. if Map[i] = -1 then
  1564. Map[i] := 1;
  1565. end;
  1566. {$IFDEF DEBUG}
  1567. // Delphi 2010 doesn't have overloads for Min/MaxValue(array of single)
  1568. // https://github.com/graphics32/graphics32/issues/153
  1569. {$IFDEF COMPILERXE1_UP}
  1570. OutputDebugString(PChar(Format('TRadialDistortionTransformation.PrepareReverseMap: MinValue(Map)=%f MaxValue(Map)=%f', [ MinValue(Map), MaxValue(Map) ])));
  1571. {$ENDIF}
  1572. {$ENDIF}
  1573. end;
  1574. procedure TRadialDistortionTransformation.PrepareTransform;
  1575. var
  1576. r: TRect;
  1577. begin
  1578. if IsRectEmpty(SrcRect) then
  1579. raise Exception.Create(RCStrSrcRectIsEmpty);
  1580. TransformValid := not IsRectEmpty(SrcRect);
  1581. if Not TransformValid then
  1582. Exit;
  1583. // center / focal point relative to which all (un)distortions are calculated
  1584. FFocalPoint.x := (SrcRect.Right + SrcRect.Left) / 2;
  1585. FFocalPoint.y := (SrcRect.Bottom + SrcRect.Top) / 2;
  1586. r := MakeRect(SrcRect);
  1587. r_0 := Sqrt(2*Sqr(Min(r.Right - r.Left, r.Bottom - r.Top)))/2;
  1588. PrepareReverseMap;
  1589. end;
  1590. function TRadialDistortionTransformation.LookUpReverseMap(const r_tgt: TFloat): TFloat;
  1591. var
  1592. index: Integer;
  1593. begin
  1594. index := Trunc((r_tgt-r_tgt_min) / (r_tgt_max-r_tgt_min) * High(Map));
  1595. if not InRange(index, 0, High(Map)) then
  1596. raise Exception.Create(Format('TRadialDistortionTransformation.LookUpReverseMap: Index %d out of range (0..%d)', [ index, MapElements ]));
  1597. Result := Map[index];
  1598. end;
  1599. procedure TRadialDistortionTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
  1600. out SrcX, SrcY: TFloat);
  1601. var
  1602. r_tgt, r_src: Single;
  1603. d: TFloatPoint;
  1604. begin
  1605. d.x := DstX;
  1606. d.y := DstY;
  1607. r_tgt := Distance(FFocalPoint, d)/r_0;
  1608. r_src := LookUpReverseMap(r_tgt);
  1609. SrcX := FFocalPoint.X + (d.X-FFocalPoint.X) / r_src;
  1610. SrcY := FFocalPoint.Y + (d.Y-FFocalPoint.Y) / r_src;
  1611. end;
  1612. procedure TRadialDistortionTransformation.SetCoefficient1(const Value: TFloat);
  1613. begin
  1614. FCoefficient1 := Value;
  1615. Changed;
  1616. end;
  1617. procedure TRadialDistortionTransformation.SetCoefficient2(const Value: TFloat);
  1618. begin
  1619. FCoefficient2 := Value;
  1620. Changed;
  1621. end;
  1622. procedure TRadialDistortionTransformation.SetScale(const Value: TFloat);
  1623. begin
  1624. FScale := Value;
  1625. Changed;
  1626. end;
  1627. procedure TRadialDistortionTransformation.SetMapElements(const Value: Integer);
  1628. begin
  1629. FMapElements := Value;
  1630. Changed;
  1631. end;
  1632. procedure TRadialDistortionTransformation.TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat);
  1633. var
  1634. r_tgt, r_src: Single;
  1635. d: TFloatPoint;
  1636. begin
  1637. d.x := SrcX;
  1638. d.y := SrcY;
  1639. r_src := Distance(FFocalPoint, d)/r_0;
  1640. r_tgt := Scale*(1 + FCoefficient1 * Sqr(r_src) + FCoefficient2 * Power(r_src, 4));
  1641. DstX := FFocalPoint.X + (d.X-FFocalPoint.X) * r_tgt;
  1642. DstY := FFocalPoint.Y + (d.Y-FFocalPoint.Y) * r_tgt;
  1643. end;
  1644. { TRemapTransformation }
  1645. constructor TRemapTransformation.Create;
  1646. begin
  1647. inherited;
  1648. FScalingFixed := FixedPoint(1, 1);
  1649. FScalingFloat := FloatPoint(1, 1);
  1650. FOffset := FloatPoint(0,0);
  1651. FVectorMap := TVectorMap.Create;
  1652. //Ensuring initial setup to avoid exceptions
  1653. FVectorMap.SetSize(1, 1);
  1654. end;
  1655. destructor TRemapTransformation.Destroy;
  1656. begin
  1657. FVectorMap.Free;
  1658. inherited;
  1659. end;
  1660. function TRemapTransformation.GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect;
  1661. const
  1662. InfRect: TFloatRect = (Left: -Infinity; Top: -Infinity; Right: Infinity; Bottom: Infinity);
  1663. begin
  1664. // We can't predict the ultimate bounds without transforming each vector in
  1665. // the vector map, return the absolute biggest possible transformation bounds
  1666. Result := InfRect;
  1667. end;
  1668. function TRemapTransformation.HasTransformedBounds: Boolean;
  1669. begin
  1670. Result := False;
  1671. end;
  1672. procedure TRemapTransformation.PrepareTransform;
  1673. begin
  1674. if IsRectEmpty(SrcRect) then
  1675. raise Exception.Create(RCStrSrcRectIsEmpty);
  1676. if IsRectEmpty(FMappingRect) then
  1677. raise Exception.Create(RCStrMappingRectIsEmpty);
  1678. with SrcRect do
  1679. begin
  1680. FSrcTranslationFloat.X := Left;
  1681. FSrcTranslationFloat.Y := Top;
  1682. FSrcScaleFloat.X := (Right - Left) / (FVectorMap.Width - 1);
  1683. FSrcScaleFloat.Y := (Bottom - Top) / (FVectorMap.Height - 1);
  1684. FSrcTranslationFixed := FixedPoint(FSrcTranslationFloat);
  1685. FSrcScaleFixed := FixedPoint(FSrcScaleFloat);
  1686. end;
  1687. with FMappingRect do
  1688. begin
  1689. FDstTranslationFloat.X := Left;
  1690. FDstTranslationFloat.Y := Top;
  1691. FDstScaleFloat.X := (FVectorMap.Width - 1) / (Right - Left);
  1692. FDstScaleFloat.Y := (FVectorMap.Height - 1) / (Bottom - Top);
  1693. FCombinedScalingFloat.X := FDstScaleFloat.X * FScalingFloat.X;
  1694. FCombinedScalingFloat.Y := FDstScaleFloat.Y * FScalingFloat.Y;
  1695. FCombinedScalingFixed := FixedPoint(FCombinedScalingFloat);
  1696. FDstTranslationFixed := FixedPoint(FDstTranslationFloat);
  1697. FDstScaleFixed := FixedPoint(FDstScaleFloat);
  1698. end;
  1699. TransformValid := True;
  1700. end;
  1701. procedure TRemapTransformation.ReverseTransformFixed(DstX, DstY: TFixed;
  1702. out SrcX, SrcY: TFixed);
  1703. begin
  1704. with FVectorMap.FixedVectorX[DstX - FOffsetFixed.X, DstY - FOffsetFixed.Y] do
  1705. begin
  1706. DstX := DstX - FDstTranslationFixed.X;
  1707. DstX := FixedMul(DstX , FDstScaleFixed.X);
  1708. DstX := DstX + FixedMul(X, FCombinedScalingFixed.X);
  1709. DstX := FixedMul(DstX, FSrcScaleFixed.X);
  1710. SrcX := DstX + FSrcTranslationFixed.X;
  1711. DstY := DstY - FDstTranslationFixed.Y;
  1712. DstY := FixedMul(DstY, FDstScaleFixed.Y);
  1713. DstY := DstY + FixedMul(Y, FCombinedScalingFixed.Y);
  1714. DstY := FixedMul(DstY, FSrcScaleFixed.Y);
  1715. SrcY := DstY + FSrcTranslationFixed.Y;
  1716. end;
  1717. end;
  1718. procedure TRemapTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
  1719. out SrcX, SrcY: TFloat);
  1720. begin
  1721. with FVectorMap.FloatVectorF[DstX - FOffset.X, DstY - FOffset.Y] do
  1722. begin
  1723. DstX := DstX - FDstTranslationFloat.X;
  1724. DstY := DstY - FDstTranslationFloat.Y;
  1725. DstX := DstX * FDstScaleFloat.X;
  1726. DstY := DstY * FDstScaleFloat.Y;
  1727. DstX := DstX + X * FCombinedScalingFloat.X;
  1728. DstY := DstY + Y * FCombinedScalingFloat.Y;
  1729. DstX := DstX * FSrcScaleFloat.X;
  1730. DstY := DstY * FSrcScaleFloat.Y;
  1731. SrcX := DstX + FSrcTranslationFloat.X;
  1732. SrcY := DstY + FSrcTranslationFloat.Y;
  1733. end;
  1734. end;
  1735. procedure TRemapTransformation.ReverseTransformInt(DstX, DstY: Integer;
  1736. out SrcX, SrcY: Integer);
  1737. begin
  1738. with FVectorMap.FixedVector[DstX - FOffsetInt.X, DstY - FOffsetInt.Y] do
  1739. begin
  1740. DstX := DstX * FixedOne - FDstTranslationFixed.X;
  1741. DstY := DstY * FixedOne - FDstTranslationFixed.Y;
  1742. DstX := FixedMul(DstX, FDstScaleFixed.X);
  1743. DstY := FixedMul(DstY, FDstScaleFixed.Y);
  1744. DstX := DstX + FixedMul(X, FCombinedScalingFixed.X);
  1745. DstY := DstY + FixedMul(Y, FCombinedScalingFixed.Y);
  1746. DstX := FixedMul(DstX, FSrcScaleFixed.X);
  1747. DstY := FixedMul(DstY, FSrcScaleFixed.Y);
  1748. SrcX := FixedRound(DstX + FSrcTranslationFixed.X);
  1749. SrcY := FixedRound(DstY + FSrcTranslationFixed.Y);
  1750. end;
  1751. end;
  1752. procedure TRemapTransformation.Scale(Sx, Sy: TFloat);
  1753. begin
  1754. FScalingFixed.X := Fixed(Sx);
  1755. FScalingFixed.Y := Fixed(Sy);
  1756. FScalingFloat.X := Sx;
  1757. FScalingFloat.Y := Sy;
  1758. Changed;
  1759. end;
  1760. procedure TRemapTransformation.SetMappingRect(Rect: TFloatRect);
  1761. begin
  1762. FMappingRect := Rect;
  1763. Changed;
  1764. end;
  1765. procedure TRemapTransformation.SetOffset(const Value: TFloatVector);
  1766. begin
  1767. FOffset := Value;
  1768. FOffsetInt := Point(Value);
  1769. FOffsetFixed := FixedPoint(Value);
  1770. Changed;
  1771. end;
  1772. procedure RasterizeTransformation(Vectormap: TVectormap;
  1773. Transformation: TTransformation; DstRect: TRect;
  1774. CombineMode: TVectorCombineMode = vcmAdd;
  1775. CombineCallback: TVectorCombineEvent = nil);
  1776. var
  1777. I, J: Integer;
  1778. P, Q, Progression: TFixedVector;
  1779. ProgressionX, ProgressionY: TFixed;
  1780. MapPtr: PFixedPointArray;
  1781. begin
  1782. GR32.IntersectRect(DstRect, VectorMap.BoundsRect, DstRect);
  1783. if GR32.IsRectEmpty(DstRect) then
  1784. Exit;
  1785. if not TTransformationAccess(Transformation).TransformValid then
  1786. TTransformationAccess(Transformation).PrepareTransform;
  1787. case CombineMode of
  1788. vcmAdd:
  1789. begin
  1790. with DstRect do
  1791. for I := Top to Bottom - 1 do
  1792. begin
  1793. MapPtr := @VectorMap.Vectors[I * VectorMap.Width];
  1794. for J := Left to Right - 1 do
  1795. begin
  1796. P := FixedPoint(Integer(J - Left), Integer(I - Top));
  1797. Q := Transformation.ReverseTransform(P);
  1798. Inc(MapPtr[J].X, Q.X - P.X);
  1799. Inc(MapPtr[J].Y, Q.Y - P.Y);
  1800. end;
  1801. end;
  1802. end;
  1803. vcmReplace:
  1804. begin
  1805. with DstRect do
  1806. for I := Top to Bottom - 1 do
  1807. begin
  1808. MapPtr := @VectorMap.Vectors[I * VectorMap.Width];
  1809. for J := Left to Right - 1 do
  1810. begin
  1811. P := FixedPoint(Integer(J - Left), Integer(I - Top));
  1812. Q := Transformation.ReverseTransform(P);
  1813. MapPtr[J].X := Q.X - P.X;
  1814. MapPtr[J].Y := Q.Y - P.Y;
  1815. end;
  1816. end;
  1817. end;
  1818. else // vcmCustom
  1819. ProgressionX := Fixed(1 / (DstRect.Right - DstRect.Left - 1));
  1820. ProgressionY := Fixed(1 / (DstRect.Bottom - DstRect.Top - 1));
  1821. Progression.Y := 0;
  1822. with DstRect do for I := Top to Bottom - 1 do
  1823. begin
  1824. Progression.X := 0;
  1825. MapPtr := @VectorMap.Vectors[I * VectorMap.Width];
  1826. for J := Left to Right - 1 do
  1827. begin
  1828. P := FixedPoint(Integer(J - Left), Integer(I - Top));
  1829. Q := Transformation.ReverseTransform(P);
  1830. Q.X := Q.X - P.X;
  1831. Q.Y := Q.Y - P.Y;
  1832. CombineCallback(Q, Progression, MapPtr[J]);
  1833. Inc(Progression.X, ProgressionX);
  1834. end;
  1835. Inc(Progression.Y, ProgressionY);
  1836. end;
  1837. end;
  1838. end;
  1839. { Matrix conversion routines }
  1840. function FixedMatrix(const FloatMatrix: TFloatMatrix): TFixedMatrix;
  1841. begin
  1842. Result[0,0] := Round(FloatMatrix[0,0] * FixedOne);
  1843. Result[0,1] := Round(FloatMatrix[0,1] * FixedOne);
  1844. Result[0,2] := Round(FloatMatrix[0,2] * FixedOne);
  1845. Result[1,0] := Round(FloatMatrix[1,0] * FixedOne);
  1846. Result[1,1] := Round(FloatMatrix[1,1] * FixedOne);
  1847. Result[1,2] := Round(FloatMatrix[1,2] * FixedOne);
  1848. Result[2,0] := Round(FloatMatrix[2,0] * FixedOne);
  1849. Result[2,1] := Round(FloatMatrix[2,1] * FixedOne);
  1850. Result[2,2] := Round(FloatMatrix[2,2] * FixedOne);
  1851. end;
  1852. function FloatMatrix(const FixedMatrix: TFixedMatrix): TFloatMatrix;
  1853. begin
  1854. Result[0,0] := FixedMatrix[0,0] * FixedToFloat;
  1855. Result[0,1] := FixedMatrix[0,1] * FixedToFloat;
  1856. Result[0,2] := FixedMatrix[0,2] * FixedToFloat;
  1857. Result[1,0] := FixedMatrix[1,0] * FixedToFloat;
  1858. Result[1,1] := FixedMatrix[1,1] * FixedToFloat;
  1859. Result[1,2] := FixedMatrix[1,2] * FixedToFloat;
  1860. Result[2,0] := FixedMatrix[2,0] * FixedToFloat;
  1861. Result[2,1] := FixedMatrix[2,1] * FixedToFloat;
  1862. Result[2,2] := FixedMatrix[2,2] * FixedToFloat;
  1863. end;
  1864. {CPU target and feature Function templates}
  1865. const
  1866. FID_DETERMINANT32 = 0;
  1867. FID_DETERMINANT64 = 1;
  1868. {Complete collection of unit templates}
  1869. var
  1870. Registry: TFunctionRegistry;
  1871. procedure RegisterBindings;
  1872. begin
  1873. Registry := NewRegistry('GR32_Transforms bindings');
  1874. Registry.RegisterBinding(FID_DETERMINANT32, @@DET32);
  1875. Registry.Add(FID_DETERMINANT32, @DET32_Pas, []);
  1876. {$IFNDEF PUREPASCAL}
  1877. Registry.Add(FID_DETERMINANT32, @DET32_ASM, []);
  1878. // Registry.Add(FID_DETERMINANT32, @DET32_SSE2, [ciSSE2]);
  1879. {$ENDIF}
  1880. Registry.RegisterBinding(FID_DETERMINANT64, @@DET64);
  1881. Registry.Add(FID_DETERMINANT64, @DET64_Pas, []);
  1882. {$IFNDEF PUREPASCAL}
  1883. Registry.Add(FID_DETERMINANT64, @DET64_ASM, []);
  1884. // Registry.Add(FID_DETERMINANT64, @DET64_SSE2, [ciSSE2]);
  1885. {$ENDIF}
  1886. Registry.RebindAll;
  1887. end;
  1888. initialization
  1889. RegisterBindings;
  1890. end.