GR32_Transforms.pas 100 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322
  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. * ***** END LICENSE BLOCK ***** *)
  31. interface
  32. {$include GR32.inc}
  33. uses
  34. {$if defined(MSWINDOWS) and defined(DEBUG)}
  35. Windows, // For OutputDebugString. In interface section so we don't override TFixed
  36. {$ifend}
  37. SysUtils,
  38. Classes,
  39. Types,
  40. GR32,
  41. GR32_VectorMaps,
  42. GR32_Rasterizers;
  43. type
  44. ETransformError = class(Exception);
  45. ETransformNotImplemented = class(Exception);
  46. type
  47. TFloatMatrix = array [0..2, 0..2] of TFloat; // 3x3 TFloat precision
  48. TFixedMatrix = array [0..2, 0..2] of TFixed; // 3x3 fixed precision
  49. const
  50. IdentityMatrix: TFloatMatrix = (
  51. (1, 0, 0),
  52. (0, 1, 0),
  53. (0, 0, 1));
  54. type
  55. TVector3f = array [0..2] of TFloat;
  56. TVector3i = array [0..2] of Integer;
  57. // Matrix conversion routines
  58. function FixedMatrix(const FloatMatrix: TFloatMatrix): TFixedMatrix; overload;
  59. function FloatMatrix(const FixedMatrix: TFixedMatrix): TFloatMatrix; overload;
  60. procedure Adjoint(var M: TFloatMatrix);
  61. function Determinant(const M: TFloatMatrix): TFloat;
  62. procedure Scale(var M: TFloatMatrix; Factor: TFloat);
  63. procedure Invert(var M: TFloatMatrix);
  64. function Mult(const M1, M2: TFloatMatrix): TFloatMatrix;
  65. function VectorTransform(const M: TFloatMatrix; const V: TVector3f): TVector3f;
  66. //------------------------------------------------------------------------------
  67. //
  68. // TTransformation
  69. //
  70. //------------------------------------------------------------------------------
  71. type
  72. TTransformation = class(TNotifiablePersistent)
  73. private
  74. FSrcRect: TFloatRect;
  75. procedure SetSrcRect(const Value: TFloatRect);
  76. protected
  77. TransformValid: Boolean;
  78. procedure PrepareTransform; virtual;
  79. procedure ReverseTransformInt(DstX, DstY: Integer; out SrcX, SrcY: Integer); virtual;
  80. procedure ReverseTransformFixed(DstX, DstY: TFixed; out SrcX, SrcY: TFixed); virtual;
  81. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); virtual;
  82. procedure TransformInt(SrcX, SrcY: Integer; out DstX, DstY: Integer); virtual;
  83. procedure TransformFixed(SrcX, SrcY: TFixed; out DstX, DstY: TFixed); virtual;
  84. procedure TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat); virtual;
  85. public
  86. constructor Create; virtual;
  87. procedure Changed; override;
  88. function HasTransformedBounds: Boolean; virtual;
  89. function GetTransformedBounds: TFloatRect; overload;
  90. function GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect; overload; virtual;
  91. function ReverseTransform(const P: TPoint): TPoint; overload; virtual;
  92. function ReverseTransform(const P: TFixedPoint): TFixedPoint; overload; virtual;
  93. function ReverseTransform(const P: TFloatPoint): TFloatPoint; overload; virtual;
  94. function Transform(const P: TPoint): TPoint; overload; virtual;
  95. function Transform(const P: TFixedPoint): TFixedPoint; overload; virtual;
  96. function Transform(const P: TFloatPoint): TFloatPoint; overload; virtual;
  97. property SrcRect: TFloatRect read FSrcRect write SetSrcRect;
  98. end;
  99. TTransformationClass = class of TTransformation;
  100. //------------------------------------------------------------------------------
  101. //
  102. // TNestedTransformation
  103. //
  104. //------------------------------------------------------------------------------
  105. type
  106. TNestedTransformation = class(TTransformation)
  107. private
  108. FItems: TList;
  109. FOwner: TPersistent;
  110. function GetCount: Integer;
  111. function GetItem(Index: Integer): TTransformation;
  112. procedure SetItem(Index: Integer; const Value: TTransformation);
  113. protected
  114. procedure PrepareTransform; override;
  115. procedure ReverseTransformFixed(DstX, DstY: TFixed; out SrcX, SrcY: TFixed); override;
  116. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  117. procedure TransformFixed(SrcX, SrcY: TFixed; out DstX, DstY: TFixed); override;
  118. procedure TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat); override;
  119. public
  120. constructor Create; override;
  121. destructor Destroy; override;
  122. function Add(ItemClass: TTransformationClass): TTransformation;
  123. procedure Clear;
  124. procedure Delete(Index: Integer);
  125. function Insert(Index: Integer; ItemClass: TTransformationClass): TTransformation;
  126. property Owner: TPersistent read FOwner;
  127. property Count: Integer read GetCount;
  128. property Items[Index: Integer]: TTransformation read GetItem write SetItem; default;
  129. end;
  130. //------------------------------------------------------------------------------
  131. //
  132. // T3x3Transformation
  133. //
  134. //------------------------------------------------------------------------------
  135. type
  136. T3x3Transformation = class(TTransformation)
  137. protected
  138. FMatrix, FInverseMatrix: TFloatMatrix;
  139. FFixedMatrix, FInverseFixedMatrix: TFixedMatrix;
  140. procedure PrepareTransform; override;
  141. procedure ReverseTransformFixed(DstX, DstY: TFixed; out SrcX, SrcY: TFixed); override;
  142. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  143. procedure TransformFixed(SrcX, SrcY: TFixed; out DstX, DstY: TFixed); override;
  144. procedure TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat); override;
  145. public
  146. property Matrix: TFloatMatrix read FMatrix;
  147. end;
  148. //------------------------------------------------------------------------------
  149. //
  150. // TAffineTransformation
  151. //
  152. //------------------------------------------------------------------------------
  153. type
  154. TAffineTransformation = class(T3x3Transformation)
  155. private
  156. FStack: ^TFloatMatrix;
  157. FStackLevel: Integer;
  158. public
  159. constructor Create; override;
  160. function GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect; override;
  161. procedure Push;
  162. procedure Pop;
  163. procedure Clear; overload;
  164. procedure Clear(BaseMatrix: TFloatMatrix); overload;
  165. procedure Rotate(Alpha: TFloat); overload; // degrees
  166. procedure Rotate(Cx, Cy, Alpha: TFloat); overload; // degrees
  167. procedure Skew(Fx, Fy: TFloat);
  168. procedure Scale(Sx, Sy: TFloat); overload;
  169. procedure Scale(Value: TFloat); overload;
  170. procedure Translate(Dx, Dy: TFloat);
  171. end;
  172. //------------------------------------------------------------------------------
  173. //
  174. // TProjectiveTransformation
  175. //
  176. //------------------------------------------------------------------------------
  177. type
  178. TProjectiveTransformation = class(T3x3Transformation)
  179. private
  180. FQuadX: array [0..3] of TFloat;
  181. FQuadY: array [0..3] of TFloat;
  182. procedure SetX(Index: Integer; const Value: TFloat); {$IFDEF UseInlining} inline; {$ENDIF}
  183. procedure SetY(Index: Integer; const Value: TFloat); {$IFDEF UseInlining} inline; {$ENDIF}
  184. function GetX(Index: Integer): TFloat; {$IFDEF UseInlining} inline; {$ENDIF}
  185. function GetY(Index: Integer): TFloat; {$IFDEF UseInlining} inline; {$ENDIF}
  186. protected
  187. procedure PrepareTransform; override;
  188. procedure ReverseTransformFixed(DstX, DstY: TFixed; out SrcX, SrcY: TFixed); override;
  189. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  190. procedure TransformFixed(SrcX, SrcY: TFixed; out DstX, DstY: TFixed); override;
  191. procedure TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat); override;
  192. public
  193. function GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect; override;
  194. property X[Index: Integer]: TFloat read GetX write SetX;
  195. property Y[index: Integer]: TFloat read GetX write SetY;
  196. published
  197. property X0: TFloat index 0 read GetX write SetX;
  198. property X1: TFloat index 1 read GetX write SetX;
  199. property X2: TFloat index 2 read GetX write SetX;
  200. property X3: TFloat index 3 read GetX write SetX;
  201. property Y0: TFloat index 0 read GetY write SetY;
  202. property Y1: TFloat index 1 read GetY write SetY;
  203. property Y2: TFloat index 2 read GetY write SetY;
  204. property Y3: TFloat index 3 read GetY write SetY;
  205. end;
  206. //------------------------------------------------------------------------------
  207. //
  208. // TProjectiveTransformationEx
  209. //
  210. //------------------------------------------------------------------------------
  211. // Performs projective transformation between two convex quadrilaterals.
  212. //------------------------------------------------------------------------------
  213. // References:
  214. //
  215. // - "Fundamentals of Texture Mapping and Image Warping"
  216. // Paul S. Heckbert
  217. // www.cs.cmu.edu/~ph/texfund/texfund.pdf
  218. //
  219. // - "Projective Mappings for ImageWarping"
  220. // Paul S. Heckbert
  221. // http://graphics.cs.cmu.edu/courses/15-463/2008_fall/Papers/proj.pdf
  222. //
  223. // - "Geometric Tools for Computer Graphics"
  224. // David H. Eberly
  225. // https://www.amazon.com/Geometric-Computer-Graphics-Morgan-Kaufmann/dp/1558605940
  226. //
  227. // - "Perspective Mappings"
  228. // David H. Eberly
  229. // https://geometrictools.com/Documentation/PerspectiveMappings.pdf
  230. //
  231. //------------------------------------------------------------------------------
  232. {$ifndef FPC} // FPC considers unicode identifiers a bug, so f*ck them and their silly toy compiler.
  233. type
  234. TQuadrilateral = array[0..3] of TPoint;
  235. TFloatQuadrilateral = array[0..3] of TFloatPoint;
  236. TProjectiveTransformationEx = class(T3x3Transformation)
  237. private
  238. FExtrapolate: boolean;
  239. FSourceQuad: TFloatQuadrilateral;
  240. FDestQuad: TFloatQuadrilateral;
  241. procedure SetSourceQuad(const Value: TFloatQuadrilateral); {$IFDEF UseInlining} inline; {$ENDIF}
  242. procedure SetDestQuad(const Value: TFloatQuadrilateral); {$IFDEF UseInlining} inline; {$ENDIF}
  243. procedure SetSource(Index: Integer; const Value: TFloatPoint); {$IFDEF UseInlining} inline; {$ENDIF}
  244. procedure SetSourceX(Index: Integer; const Value: TFloat); {$IFDEF UseInlining} inline; {$ENDIF}
  245. procedure SetSourceY(Index: Integer; const Value: TFloat); {$IFDEF UseInlining} inline; {$ENDIF}
  246. procedure SetDest(Index: Integer; const Value: TFloatPoint); {$IFDEF UseInlining} inline; {$ENDIF}
  247. procedure SetDestX(Index: Integer; const Value: TFloat); {$IFDEF UseInlining} inline; {$ENDIF}
  248. procedure SetDestY(Index: Integer; const Value: TFloat); {$IFDEF UseInlining} inline; {$ENDIF}
  249. function GetSource(Index: Integer): TFloatPoint; {$IFDEF UseInlining} inline; {$ENDIF}
  250. function GetSourceX(Index: Integer): TFloat; {$IFDEF UseInlining} inline; {$ENDIF}
  251. function GetSourceY(Index: Integer): TFloat; {$IFDEF UseInlining} inline; {$ENDIF}
  252. function GetDest(Index: Integer): TFloatPoint; {$IFDEF UseInlining} inline; {$ENDIF}
  253. function GetDestX(Index: Integer): TFloat; {$IFDEF UseInlining} inline; {$ENDIF}
  254. function GetDestY(Index: Integer): TFloat; {$IFDEF UseInlining} inline; {$ENDIF}
  255. protected
  256. procedure PrepareTransform; override;
  257. procedure ReverseTransformFixed(DstX, DstY: TFixed; out SrcX, SrcY: TFixed); override;
  258. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  259. procedure TransformFixed(SrcX, SrcY: TFixed; out DstX, DstY: TFixed); override;
  260. procedure TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat); override;
  261. public
  262. function GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect; override;
  263. property SourceQuad: TFloatQuadrilateral read FSourceQuad write SetSourceQuad;
  264. property Source[Index: Integer]: TFloatPoint read GetSource write SetSource;
  265. property SourceX[Index: Integer]: TFloat read GetSourceX write SetSourceX;
  266. property SourceY[Index: Integer]: TFloat read GetSourceY write SetSourceY;
  267. property DestQuad: TFloatQuadrilateral read FDestQuad write SetDestQuad;
  268. property Dest[Index: Integer]: TFloatPoint read GetDest write SetDest;
  269. property DestX[Index: Integer]: TFloat read GetDestX write SetDestX;
  270. property DestY[index: Integer]: TFloat read GetDestX write SetDestY;
  271. published
  272. // Set Extrapolate=True to have pixels beyond the destination be transformed.
  273. // This is done by having GetTransformedBounds return the passed source rect,
  274. // which in turn causes the rasterizer to process all pixels of the source
  275. // image instead of just the pixels covered by the target quad.
  276. property Extrapolate: boolean read FExtrapolate write FExtrapolate;
  277. property DestX0: TFloat index 0 read GetDestX write SetDestX;
  278. property DestX1: TFloat index 1 read GetDestX write SetDestX;
  279. property DestX2: TFloat index 2 read GetDestX write SetDestX;
  280. property DestX3: TFloat index 3 read GetDestX write SetDestX;
  281. property DestY0: TFloat index 0 read GetDestY write SetDestY;
  282. property DestY1: TFloat index 1 read GetDestY write SetDestY;
  283. property DestY2: TFloat index 2 read GetDestY write SetDestY;
  284. property DestY3: TFloat index 3 read GetDestY write SetDestY;
  285. property SourceX0: TFloat index 0 read GetSourceX write SetSourceX;
  286. property SourceX1: TFloat index 1 read GetSourceX write SetSourceX;
  287. property SourceX2: TFloat index 2 read GetSourceX write SetSourceX;
  288. property SourceX3: TFloat index 3 read GetSourceX write SetSourceX;
  289. property SourceY0: TFloat index 0 read GetSourceY write SetSourceY;
  290. property SourceY1: TFloat index 1 read GetSourceY write SetSourceY;
  291. property SourceY2: TFloat index 2 read GetSourceY write SetSourceY;
  292. property SourceY3: TFloat index 3 read GetSourceY write SetSourceY;
  293. end;
  294. {$endif FPC}
  295. //------------------------------------------------------------------------------
  296. //
  297. // TTwirlTransformation
  298. //
  299. //------------------------------------------------------------------------------
  300. type
  301. TTwirlTransformation = class(TTransformation)
  302. private
  303. Frx, Fry: TFloat;
  304. FTwirl: TFloat;
  305. procedure SetTwirl(const Value: TFloat);
  306. protected
  307. procedure PrepareTransform; override;
  308. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  309. public
  310. constructor Create; override;
  311. function GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect; override;
  312. published
  313. property Twirl: TFloat read FTwirl write SetTwirl;
  314. end;
  315. //------------------------------------------------------------------------------
  316. //
  317. // TBloatTransformation
  318. //
  319. //------------------------------------------------------------------------------
  320. type
  321. TBloatTransformation = class(TTransformation)
  322. private
  323. FBloatPower: TFloat;
  324. FBP: TFloat;
  325. FPiW, FPiH: TFloat;
  326. procedure SetBloatPower(const Value: TFloat);
  327. protected
  328. procedure PrepareTransform; override;
  329. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  330. procedure TransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  331. public
  332. constructor Create; override;
  333. published
  334. property BloatPower: TFloat read FBloatPower write SetBloatPower;
  335. end;
  336. //------------------------------------------------------------------------------
  337. //
  338. // TDisturbanceTransformation
  339. //
  340. //------------------------------------------------------------------------------
  341. type
  342. TDisturbanceTransformation = class(TTransformation)
  343. private
  344. FDisturbance: TFloat;
  345. procedure SetDisturbance(const Value: TFloat);
  346. protected
  347. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  348. public
  349. function GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect; override;
  350. published
  351. property Disturbance: TFloat read FDisturbance write SetDisturbance;
  352. end;
  353. //------------------------------------------------------------------------------
  354. //
  355. // TFishEyeTransformation
  356. //
  357. //------------------------------------------------------------------------------
  358. type
  359. TFishEyeTransformation = class(TTransformation)
  360. private
  361. Frx, Fry: TFloat;
  362. Faw, Fsr: TFloat;
  363. Sx, Sy: TFloat;
  364. FMinR: TFloat;
  365. protected
  366. procedure PrepareTransform; override;
  367. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  368. end;
  369. //------------------------------------------------------------------------------
  370. //
  371. // TPolarTransformation
  372. //
  373. //------------------------------------------------------------------------------
  374. type
  375. TPolarTransformation = class(TTransformation)
  376. private
  377. FDstRect: TFloatRect;
  378. FPhase: TFloat;
  379. Sx, Sy, Cx, Cy, Dx, Dy, Rt, Rt2, Rr, Rcx, Rcy: TFloat;
  380. procedure SetDstRect(const Value: TFloatRect);
  381. procedure SetPhase(const Value: TFloat);
  382. protected
  383. procedure PrepareTransform; override;
  384. procedure TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat); override;
  385. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  386. public
  387. property DstRect: TFloatRect read FDstRect write SetDstRect;
  388. property Phase: TFloat read FPhase write SetPhase;
  389. end;
  390. //------------------------------------------------------------------------------
  391. //
  392. // TPathTransformation
  393. //
  394. //------------------------------------------------------------------------------
  395. type
  396. TPathTransformation = class(TTransformation)
  397. private
  398. FTopLength: TFloat;
  399. FBottomLength: TFloat;
  400. FBottomCurve: TArrayOfFloatPoint;
  401. FTopCurve: TArrayOfFloatPoint;
  402. FTopHypot, FBottomHypot: array of record Dist, RecDist: TFloat end;
  403. procedure SetBottomCurve(const Value: TArrayOfFloatPoint);
  404. procedure SetTopCurve(const Value: TArrayOfFloatPoint);
  405. protected
  406. rdx, rdy: TFloat;
  407. procedure PrepareTransform; override;
  408. procedure TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat); override;
  409. public
  410. destructor Destroy; override;
  411. property TopCurve: TArrayOfFloatPoint read FTopCurve write SetTopCurve;
  412. property BottomCurve: TArrayOfFloatPoint read FBottomCurve write SetBottomCurve;
  413. end;
  414. //------------------------------------------------------------------------------
  415. //
  416. // TRadialDistortionTransformation
  417. //
  418. //------------------------------------------------------------------------------
  419. type
  420. TRadialDistortionTransformation = class(TTransformation)
  421. protected
  422. FCoefficient1, FCoefficient2, FScale: TFloat;
  423. FFocalPoint: TFloatPoint;
  424. r_0, r_tgt_max, r_tgt_min: Single;
  425. FMapElements: Integer;
  426. Map: Array of TFloat;
  427. function LookUpReverseMap(const r_tgt: TFloat): TFloat;
  428. procedure SetCoefficient1(const Value: TFloat);
  429. procedure SetCoefficient2(const Value: TFloat);
  430. procedure SetScale(const Value: TFloat);
  431. procedure SetMapElements(const Value: Integer);
  432. procedure PrepareReverseMap;
  433. procedure PrepareTransform; override;
  434. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  435. procedure TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat); override;
  436. public
  437. constructor Create; override;
  438. function HasTransformedBounds: Boolean; override;
  439. published
  440. property Coefficient1: TFloat read FCoefficient1 write SetCoefficient1;
  441. property Coefficient2: TFloat read FCoefficient2 write SetCoefficient2;
  442. property Scale: TFloat read FScale write SetScale;
  443. property MapElements: Integer read FMapElements write SetMapElements;
  444. end;
  445. //------------------------------------------------------------------------------
  446. //
  447. // TRemapTransformation
  448. //
  449. //------------------------------------------------------------------------------
  450. type
  451. TRemapTransformation = class(TTransformation)
  452. private
  453. FVectorMap: TVectorMap;
  454. FScalingFixed: TFixedVector;
  455. FScalingFloat: TFloatVector;
  456. FCombinedScalingFixed: TFixedVector;
  457. FCombinedScalingFloat: TFloatVector;
  458. FSrcTranslationFixed: TFixedVector;
  459. FSrcScaleFixed: TFixedVector;
  460. FDstTranslationFixed: TFixedVector;
  461. FDstScaleFixed: TFixedVector;
  462. FSrcTranslationFloat: TFloatVector;
  463. FSrcScaleFloat: TFloatVector;
  464. FDstTranslationFloat: TFloatVector;
  465. FDstScaleFloat: TFloatVector;
  466. FOffsetFixed : TFixedVector;
  467. FOffsetInt : TPoint;
  468. FMappingRect: TFloatRect;
  469. FOffset: TFloatVector;
  470. procedure SetMappingRect(Rect: TFloatRect);
  471. procedure SetOffset(const Value: TFloatVector);
  472. protected
  473. procedure PrepareTransform; override;
  474. procedure ReverseTransformInt(DstX, DstY: Integer; out SrcX, SrcY: Integer); override;
  475. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  476. procedure ReverseTransformFixed(DstX, DstY: TFixed; out SrcX, SrcY: TFixed); override;
  477. public
  478. constructor Create; override;
  479. destructor Destroy; override;
  480. function HasTransformedBounds: Boolean; override;
  481. function GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect; override;
  482. procedure Scale(Sx, Sy: TFloat);
  483. property MappingRect: TFloatRect read FMappingRect write SetMappingRect;
  484. property Offset: TFloatVector read FOffset write SetOffset;
  485. property VectorMap: TVectorMap read FVectorMap write FVectorMap;
  486. end;
  487. //------------------------------------------------------------------------------
  488. //
  489. // TSphereTransformation
  490. //
  491. //------------------------------------------------------------------------------
  492. // Transform a map (planisphere) into a Spherical projection.
  493. // By Marc LAFON (marc.lafon AT free.fr), 01 nov 2005
  494. //------------------------------------------------------------------------------
  495. type
  496. TSphereTransformation = class(TTransformation)
  497. private
  498. FMapWidth, FMapHeight: TFloat;
  499. FSquareRadius: TFloat;
  500. FCenter: TFloatPoint;
  501. FRadius: TFloat;
  502. FLongitude: TFloat;
  503. FLattitude: TFloat;
  504. FLattitudeSin: TFloat;
  505. FLattitudeCos: TFloat;
  506. FLattitudeSinInvRadius: TFloat;
  507. FLattitudeCosInvRadius: TFloat;
  508. FSrcRectTop: TFloat;
  509. FSrcRectLeft: TFloat;
  510. procedure SetCenter(const Value: TFloatPoint);
  511. procedure SetLattitude(const Value: TFloat);
  512. procedure SetLongitude(const Value: TFloat);
  513. procedure SetRadius(const Value: TFloat);
  514. protected
  515. procedure PrepareTransform; override;
  516. procedure ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat); override;
  517. public
  518. constructor Create; override;
  519. function HasTransformedBounds: Boolean; override;
  520. function GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect; override;
  521. // Return True if the (X,Y) point is in the Sphere projection
  522. function IsInSphere(CartesianX, CartesianY: TFloat):boolean;
  523. // Transform (X,Y) coordinate as Lattitude and Longitude coordinates in the Sphere
  524. function SphericalCoordinate(CartesianX, CartesianY: TFloat):TFloatPoint;
  525. // Transform Longitude and Lattitude coordinates (X,Y) into their screen projection.
  526. // Returns False if this point is on visible face.
  527. function ScreenCoordinate(var X, Y: TFloat):boolean;
  528. // Center of the Sphere in the Destination Bitmap
  529. property Center: TFloatPoint read FCenter write SetCenter;
  530. // Radius of the Sphere in the Destination Bitmap
  531. property Radius: TFloat read FRadius write SetRadius;
  532. // Rotation of the Sphere (Y-axe rotation angle)
  533. property Lattitude: TFloat read FLattitude write SetLattitude;
  534. // Rotation of the Sphere (X-axe rotation angle)
  535. property Longitude: TFloat read FLongitude write SetLongitude;
  536. end;
  537. //------------------------------------------------------------------------------
  538. //
  539. // Utilities
  540. //
  541. //------------------------------------------------------------------------------
  542. function TransformPoints(Points: TArrayOfArrayOfFixedPoint; Transformation: TTransformation): TArrayOfArrayOfFixedPoint;
  543. procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation; Reverse: boolean = True); overload;
  544. procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation; const DstClip: TRect; Reverse: boolean = True); overload;
  545. procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation; Rasterizer: TRasterizer; Reverse: boolean = True); overload;
  546. procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation; Rasterizer: TRasterizer; const DstClip: TRect; Reverse: boolean = True); overload;
  547. procedure RasterizeTransformation(Vectormap: TVectormap;
  548. Transformation: TTransformation; DstRect: TRect;
  549. CombineMode: TVectorCombineMode = vcmAdd;
  550. CombineCallback: TVectorCombineEvent = nil);
  551. procedure SetBorderTransparent(ABitmap: TCustomBitmap32; ARect: TRect);
  552. //------------------------------------------------------------------------------
  553. { FullEdge controls how the bitmap is resampled }
  554. var
  555. FullEdge: Boolean = True;
  556. resourcestring
  557. RCStrReverseTransformationNotImplemented = 'Reverse transformation is not implemented in %s.';
  558. RCStrForwardTransformationNotImplemented = 'Forward transformation is not implemented in %s.';
  559. RCStrTopBottomCurveNil = 'Top or bottom curve is nil';
  560. //------------------------------------------------------------------------------
  561. //------------------------------------------------------------------------------
  562. //------------------------------------------------------------------------------
  563. implementation
  564. uses
  565. Math,
  566. GR32_Blend,
  567. GR32_LowLevel,
  568. GR32_Math,
  569. GR32_Bindings,
  570. GR32_Resamplers,
  571. GR32_Geometry;
  572. resourcestring
  573. RCStrSrcRectIsEmpty = 'SrcRect is empty!';
  574. RCStrMappingRectIsEmpty = 'MappingRect is empty!';
  575. RStrStackEmpty = 'Stack empty';
  576. type
  577. { provides access to proctected members of TTransformation by typecasting }
  578. TTransformationAccess = class(TTransformation);
  579. //------------------------------------------------------------------------------
  580. //
  581. // A bit of linear algebra
  582. //
  583. //------------------------------------------------------------------------------
  584. var
  585. DET_2x2_32: function(a1, a2, b1, b2: TFloat): TFloat;
  586. DET_3x3_32: function(a1, a2, a3, b1, b2, b3, c1, c2, c3: TFloat): TFloat;
  587. DET_2x2_64: function(a1, a2, b1, b2: Double): Double;
  588. //------------------------------------------------------------------------------
  589. // DET_2x2_32
  590. //------------------------------------------------------------------------------
  591. function DET_2x2_32_Pas(a1, a2, b1, b2: TFloat): TFloat;
  592. begin
  593. Result := a1 * b2 - a2 * b1;
  594. end;
  595. {$IFNDEF PUREPASCAL}
  596. {$if defined(TARGET_x86)}
  597. function DET_2x2_32_ASM(a1, a2, b1, b2: TFloat): TFloat; {$IFDEF FPC}assembler; {$ENDIF}
  598. asm
  599. FLD A1.Single
  600. FMUL B2.Single
  601. FLD A2.Single
  602. FMUL B1.Single
  603. FSUBP
  604. end;
  605. {$elseif defined(TARGET_x64)}
  606. function DET_2x2_32_SSE(a1, a2, b1, b2: TFloat): TFloat; {$IFDEF FPC}assembler; nostackframe;{$ENDIF}
  607. asm
  608. // XMM0: a1
  609. // XMM1: a2
  610. // XMM2: b1
  611. // XMM3: b2
  612. MULSS XMM0, XMM3 // XMM0 <- a1 * b2
  613. MULSS XMM1, XMM2 // XMM1 <- a2 * b1
  614. SUBSS XMM0, XMM1 // Result <- (a1 * b2) - (a2 * b1)
  615. end;
  616. {$ifend}
  617. {$ENDIF}
  618. //------------------------------------------------------------------------------
  619. // DET_2x2_64
  620. //------------------------------------------------------------------------------
  621. function DET_2x2_64_Pas(a1, a2, b1, b2: Double): Double; overload;
  622. begin
  623. Result := a1 * b2 - a2 * b1;
  624. end;
  625. {$IFNDEF PUREPASCAL}
  626. {$if defined(TARGET_x86)}
  627. function DET_2x2_64_ASM(a1, a2, b1, b2: Double): Double; {$IFDEF FPC}assembler; {$ENDIF}
  628. asm
  629. FLD A1.Double
  630. FMUL B2.Double
  631. FLD A2.Double
  632. FMUL B1.Double
  633. FSUBP
  634. end;
  635. {$elseif defined(TARGET_x64)}
  636. function DET_2x2_64_SSE(a1, a2, b1, b2: Double): Double; {$IFDEF FPC}assembler; nostackframe;{$ENDIF}
  637. asm
  638. // XMM0: a1
  639. // XMM1: a2
  640. // XMM2: b1
  641. // XMM3: b2
  642. MULSD XMM0, XMM3 // XMM0 <- a1 * b2
  643. MULSD XMM1, XMM2 // XMM1 <- a2 * b1
  644. SUBSD XMM0, XMM1 // Result <- (a1 * b2) - (a2 * b1)
  645. end;
  646. {$ifend}
  647. {$ENDIF}
  648. //------------------------------------------------------------------------------
  649. // DET_3x3_32
  650. //------------------------------------------------------------------------------
  651. function DET_3x3_32_Pas(a1, a2, a3, b1, b2, b3, c1, c2, c3: TFloat): TFloat; overload; {$IFDEF UseInlining} inline; {$ENDIF}
  652. begin
  653. Result :=
  654. a1 * (b2 * c3 - b3 * c2) -
  655. b1 * (a2 * c3 - a3 * c2) +
  656. c1 * (a2 * b3 - a3 * b2);
  657. end;
  658. //------------------------------------------------------------------------------
  659. //
  660. // Utilities
  661. //
  662. //------------------------------------------------------------------------------
  663. procedure Adjoint(var M: TFloatMatrix);
  664. var
  665. Tmp: TFloatMatrix;
  666. begin
  667. Tmp := M;
  668. M[0,0] := DET_2x2_32(Tmp[1,1], Tmp[1,2], Tmp[2,1], Tmp[2,2]);
  669. M[0,1] := -DET_2x2_32(Tmp[0,1], Tmp[0,2], Tmp[2,1], Tmp[2,2]);
  670. M[0,2] := DET_2x2_32(Tmp[0,1], Tmp[0,2], Tmp[1,1], Tmp[1,2]);
  671. M[1,0] := -DET_2x2_32(Tmp[1,0], Tmp[1,2], Tmp[2,0], Tmp[2,2]);
  672. M[1,1] := DET_2x2_32(Tmp[0,0], Tmp[0,2], Tmp[2,0], Tmp[2,2]);
  673. M[1,2] := -DET_2x2_32(Tmp[0,0], Tmp[0,2], Tmp[1,0], Tmp[1,2]);
  674. M[2,0] := DET_2x2_32(Tmp[1,0], Tmp[1,1], Tmp[2,0], Tmp[2,1]);
  675. M[2,1] := -DET_2x2_32(Tmp[0,0], Tmp[0,1], Tmp[2,0], Tmp[2,1]);
  676. M[2,2] := DET_2x2_32(Tmp[0,0], Tmp[0,1], Tmp[1,0], Tmp[1,1]);
  677. end;
  678. //------------------------------------------------------------------------------
  679. function Determinant(const M: TFloatMatrix): TFloat;
  680. begin
  681. Result := DET_3x3_32_Pas(
  682. M[0,0], M[1,0], M[2,0],
  683. M[0,1], M[1,1], M[2,1],
  684. M[0,2], M[1,2], M[2,2]);
  685. end;
  686. //------------------------------------------------------------------------------
  687. procedure Scale(var M: TFloatMatrix; Factor: TFloat);
  688. var
  689. i, j: Integer;
  690. begin
  691. for i := 0 to 2 do
  692. for j := 0 to 2 do
  693. M[i,j] := M[i,j] * Factor;
  694. end;
  695. //------------------------------------------------------------------------------
  696. procedure Invert(var M: TFloatMatrix);
  697. var
  698. Det: TFloat;
  699. begin
  700. Det := Determinant(M);
  701. if Abs(Det) < 1E-5 then
  702. M := IdentityMatrix
  703. else
  704. begin
  705. Adjoint(M);
  706. Scale(M, 1 / Det);
  707. end;
  708. end;
  709. //------------------------------------------------------------------------------
  710. function Mult(const M1, M2: TFloatMatrix): TFloatMatrix;
  711. var
  712. i, j: Integer;
  713. begin
  714. for i := 0 to 2 do
  715. for j := 0 to 2 do
  716. Result[i, j] :=
  717. M1[0, j] * M2[i, 0] +
  718. M1[1, j] * M2[i, 1] +
  719. M1[2, j] * M2[i, 2];
  720. end;
  721. //------------------------------------------------------------------------------
  722. function VectorTransform(const M: TFloatMatrix; const V: TVector3f): TVector3f;
  723. begin
  724. Result[0] := M[0,0] * V[0] + M[1,0] * V[1] + M[2,0] * V[2];
  725. Result[1] := M[0,1] * V[0] + M[1,1] * V[1] + M[2,1] * V[2];
  726. Result[2] := M[0,2] * V[0] + M[1,2] * V[1] + M[2,2] * V[2];
  727. end;
  728. //------------------------------------------------------------------------------
  729. procedure SetBorderTransparent(ABitmap: TCustomBitmap32; ARect: TRect);
  730. var
  731. I: Integer;
  732. begin
  733. GR32.IntersectRect(ARect, ARect, ABitmap.BoundsRect);
  734. with ARect, ABitmap do
  735. if (Right > Left) and (Bottom > Top) and
  736. (Left < ClipRect.Right) and (Top < ClipRect.Bottom) and
  737. (Right > ClipRect.Left) and (Bottom > ClipRect.Top) then
  738. begin
  739. Dec(Right);
  740. Dec(Bottom);
  741. for I := Left to Right do
  742. begin
  743. ABitmap[I, Top] := ABitmap[I, Top] and $00FFFFFF;
  744. ABitmap[I, Bottom] := ABitmap[I, Bottom] and $00FFFFFF;
  745. end;
  746. for I := Top to Bottom do
  747. begin
  748. ABitmap[Left, I] := ABitmap[Left, I] and $00FFFFFF;
  749. ABitmap[Right, I] := ABitmap[Right, I] and $00FFFFFF;
  750. end;
  751. Changed;
  752. end;
  753. end;
  754. //------------------------------------------------------------------------------
  755. // Transformation functions
  756. //------------------------------------------------------------------------------
  757. function TransformPoints(Points: TArrayOfArrayOfFixedPoint; Transformation: TTransformation): TArrayOfArrayOfFixedPoint;
  758. var
  759. I, J: Integer;
  760. begin
  761. if Points = nil then
  762. Result := nil
  763. else
  764. begin
  765. SetLength(Result, Length(Points));
  766. Transformation.PrepareTransform;
  767. for I := 0 to High(Result) do
  768. begin
  769. SetLength(Result[I], Length(Points[I]));
  770. if Length(Result[I]) > 0 then
  771. for J := 0 to High(Result[I]) do
  772. Transformation.TransformFixed(Points[I][J].X, Points[I][J].Y, Result[I][J].X, Result[I][J].Y);
  773. end;
  774. end;
  775. end;
  776. //------------------------------------------------------------------------------
  777. procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation; Reverse: boolean);
  778. var
  779. Rasterizer: TRasterizer;
  780. begin
  781. Rasterizer := DefaultRasterizerClass.Create;
  782. try
  783. Transform(Dst, Src, Transformation, Rasterizer, Reverse);
  784. finally
  785. Rasterizer.Free;
  786. end;
  787. end;
  788. //------------------------------------------------------------------------------
  789. procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation; const DstClip: TRect; Reverse: boolean);
  790. var
  791. Rasterizer: TRasterizer;
  792. begin
  793. Rasterizer := DefaultRasterizerClass.Create;
  794. try
  795. Transform(Dst, Src, Transformation, Rasterizer, DstClip, Reverse);
  796. finally
  797. Rasterizer.Free;
  798. end;
  799. end;
  800. //------------------------------------------------------------------------------
  801. procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation;
  802. Rasterizer: TRasterizer; Reverse: boolean);
  803. begin
  804. Transform(Dst, Src, Transformation, Rasterizer, Dst.BoundsRect, Reverse);
  805. end;
  806. //------------------------------------------------------------------------------
  807. procedure Transform(Dst, Src: TCustomBitmap32; Transformation: TTransformation;
  808. Rasterizer: TRasterizer; const DstClip: TRect; Reverse: boolean);
  809. var
  810. DstRect: TRect;
  811. Transformer: TTransformer;
  812. begin
  813. GR32.IntersectRect(DstRect, DstClip, Dst.ClipRect);
  814. if (DstRect.Right < DstRect.Left) or (DstRect.Bottom < DstRect.Top) then
  815. Exit;
  816. if not Dst.MeasuringMode then
  817. begin
  818. Transformer := TTransformer.Create(Src.Resampler, Transformation, Reverse);
  819. try
  820. Rasterizer.Sampler := Transformer;
  821. Rasterizer.Rasterize(Dst, DstRect, Src);
  822. finally
  823. Transformer.Free;
  824. end;
  825. end;
  826. Dst.Changed(DstRect);
  827. end;
  828. //------------------------------------------------------------------------------
  829. procedure RasterizeTransformation(Vectormap: TVectormap;
  830. Transformation: TTransformation; DstRect: TRect;
  831. CombineMode: TVectorCombineMode = vcmAdd;
  832. CombineCallback: TVectorCombineEvent = nil);
  833. var
  834. I, J: Integer;
  835. P, Q, Progression: TFixedVector;
  836. ProgressionX, ProgressionY: TFixed;
  837. MapPtr: PFixedPointArray;
  838. begin
  839. GR32.IntersectRect(DstRect, VectorMap.BoundsRect, DstRect);
  840. if GR32.IsRectEmpty(DstRect) then
  841. Exit;
  842. if not TTransformationAccess(Transformation).TransformValid then
  843. TTransformationAccess(Transformation).PrepareTransform;
  844. case CombineMode of
  845. vcmAdd:
  846. begin
  847. with DstRect do
  848. for I := Top to Bottom - 1 do
  849. begin
  850. MapPtr := @VectorMap.Vectors[I * VectorMap.Width];
  851. for J := Left to Right - 1 do
  852. begin
  853. P := FixedPoint(Integer(J - Left), Integer(I - Top));
  854. Q := Transformation.ReverseTransform(P);
  855. Inc(MapPtr[J].X, Q.X - P.X);
  856. Inc(MapPtr[J].Y, Q.Y - P.Y);
  857. end;
  858. end;
  859. end;
  860. vcmReplace:
  861. begin
  862. with DstRect do
  863. for I := Top to Bottom - 1 do
  864. begin
  865. MapPtr := @VectorMap.Vectors[I * VectorMap.Width];
  866. for J := Left to Right - 1 do
  867. begin
  868. P := FixedPoint(Integer(J - Left), Integer(I - Top));
  869. Q := Transformation.ReverseTransform(P);
  870. MapPtr[J].X := Q.X - P.X;
  871. MapPtr[J].Y := Q.Y - P.Y;
  872. end;
  873. end;
  874. end;
  875. else // vcmCustom
  876. ProgressionX := Fixed(1 / (DstRect.Right - DstRect.Left - 1));
  877. ProgressionY := Fixed(1 / (DstRect.Bottom - DstRect.Top - 1));
  878. Progression.Y := 0;
  879. with DstRect do for I := Top to Bottom - 1 do
  880. begin
  881. Progression.X := 0;
  882. MapPtr := @VectorMap.Vectors[I * VectorMap.Width];
  883. for J := Left to Right - 1 do
  884. begin
  885. P := FixedPoint(Integer(J - Left), Integer(I - Top));
  886. Q := Transformation.ReverseTransform(P);
  887. Q.X := Q.X - P.X;
  888. Q.Y := Q.Y - P.Y;
  889. CombineCallback(Q, Progression, MapPtr[J]);
  890. Inc(Progression.X, ProgressionX);
  891. end;
  892. Inc(Progression.Y, ProgressionY);
  893. end;
  894. end;
  895. end;
  896. //------------------------------------------------------------------------------
  897. // Matrix conversion routines
  898. //------------------------------------------------------------------------------
  899. function FixedMatrix(const FloatMatrix: TFloatMatrix): TFixedMatrix;
  900. begin
  901. Result[0,0] := Round(FloatMatrix[0,0] * FixedOne);
  902. Result[0,1] := Round(FloatMatrix[0,1] * FixedOne);
  903. Result[0,2] := Round(FloatMatrix[0,2] * FixedOne);
  904. Result[1,0] := Round(FloatMatrix[1,0] * FixedOne);
  905. Result[1,1] := Round(FloatMatrix[1,1] * FixedOne);
  906. Result[1,2] := Round(FloatMatrix[1,2] * FixedOne);
  907. Result[2,0] := Round(FloatMatrix[2,0] * FixedOne);
  908. Result[2,1] := Round(FloatMatrix[2,1] * FixedOne);
  909. Result[2,2] := Round(FloatMatrix[2,2] * FixedOne);
  910. end;
  911. function FloatMatrix(const FixedMatrix: TFixedMatrix): TFloatMatrix;
  912. begin
  913. Result[0,0] := FixedMatrix[0,0] * FixedToFloat;
  914. Result[0,1] := FixedMatrix[0,1] * FixedToFloat;
  915. Result[0,2] := FixedMatrix[0,2] * FixedToFloat;
  916. Result[1,0] := FixedMatrix[1,0] * FixedToFloat;
  917. Result[1,1] := FixedMatrix[1,1] * FixedToFloat;
  918. Result[1,2] := FixedMatrix[1,2] * FixedToFloat;
  919. Result[2,0] := FixedMatrix[2,0] * FixedToFloat;
  920. Result[2,1] := FixedMatrix[2,1] * FixedToFloat;
  921. Result[2,2] := FixedMatrix[2,2] * FixedToFloat;
  922. end;
  923. //------------------------------------------------------------------------------
  924. //
  925. // TTransformation
  926. //
  927. //------------------------------------------------------------------------------
  928. function TTransformation.GetTransformedBounds: TFloatRect;
  929. begin
  930. Result := GetTransformedBounds(FSrcRect);
  931. end;
  932. procedure TTransformation.Changed;
  933. begin
  934. TransformValid := False;
  935. inherited;
  936. end;
  937. constructor TTransformation.Create;
  938. begin
  939. // virtual constructor to be overriden in derived classes
  940. end;
  941. function TTransformation.GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect;
  942. begin
  943. Result := ASrcRect;
  944. end;
  945. function TTransformation.HasTransformedBounds: Boolean;
  946. begin
  947. Result := True;
  948. end;
  949. procedure TTransformation.PrepareTransform;
  950. begin
  951. // Dummy
  952. end;
  953. function TTransformation.ReverseTransform(const P: TFloatPoint): TFloatPoint;
  954. begin
  955. if not TransformValid then
  956. PrepareTransform;
  957. ReverseTransformFloat(P.X, P.Y, Result.X, Result.Y);
  958. end;
  959. function TTransformation.ReverseTransform(const P: TFixedPoint): TFixedPoint;
  960. begin
  961. if not TransformValid then
  962. PrepareTransform;
  963. ReverseTransformFixed(P.X, P.Y, Result.X, Result.Y);
  964. end;
  965. function TTransformation.ReverseTransform(const P: TPoint): TPoint;
  966. begin
  967. if not TransformValid then
  968. PrepareTransform;
  969. ReverseTransformInt(P.X, P.Y, Result.X, Result.Y);
  970. end;
  971. procedure TTransformation.ReverseTransformFixed(DstX, DstY: TFixed; out SrcX, SrcY: TFixed);
  972. var
  973. X, Y: TFloat;
  974. begin
  975. ReverseTransformFloat(DstX * FixedToFloat, DstY * FixedToFloat, X, Y);
  976. SrcX := Fixed(X);
  977. SrcY := Fixed(Y);
  978. end;
  979. procedure TTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
  980. out SrcX, SrcY: TFloat);
  981. begin
  982. // ReverseTransformFloat is the top precisionlevel, all descendants must override at least this level!
  983. raise ETransformNotImplemented.CreateFmt(RCStrReverseTransformationNotImplemented, [Self.Classname]);
  984. end;
  985. procedure TTransformation.ReverseTransformInt(DstX, DstY: Integer;
  986. out SrcX, SrcY: Integer);
  987. var
  988. X, Y: TFixed;
  989. begin
  990. ReverseTransformFixed(DstX shl 16, DstY shl 16, X, Y);
  991. SrcX := FixedRound(X);
  992. SrcY := FixedRound(Y);
  993. end;
  994. procedure TTransformation.SetSrcRect(const Value: TFloatRect);
  995. begin
  996. FSrcRect := Value;
  997. Changed;
  998. end;
  999. function TTransformation.Transform(const P: TFloatPoint): TFloatPoint;
  1000. begin
  1001. if not TransformValid then
  1002. PrepareTransform;
  1003. TransformFloat(P.X, P.Y, Result.X, Result.Y);
  1004. end;
  1005. function TTransformation.Transform(const P: TFixedPoint): TFixedPoint;
  1006. begin
  1007. if not TransformValid then
  1008. PrepareTransform;
  1009. TransformFixed(P.X, P.Y, Result.X, Result.Y);
  1010. end;
  1011. function TTransformation.Transform(const P: TPoint): TPoint;
  1012. begin
  1013. if not TransformValid then
  1014. PrepareTransform;
  1015. TransformInt(P.X, P.Y, Result.X, Result.Y);
  1016. end;
  1017. procedure TTransformation.TransformFixed(SrcX, SrcY: TFixed; out DstX,
  1018. DstY: TFixed);
  1019. var
  1020. X, Y: TFloat;
  1021. begin
  1022. TransformFloat(SrcX * FixedToFloat, SrcY * FixedToFloat, X, Y);
  1023. DstX := Fixed(X);
  1024. DstY := Fixed(Y);
  1025. end;
  1026. procedure TTransformation.TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat);
  1027. begin
  1028. // TransformFloat is the top precisionlevel, all descendants must override at least this level!
  1029. raise ETransformNotImplemented.CreateFmt(RCStrForwardTransformationNotImplemented, [Self.Classname]);
  1030. end;
  1031. procedure TTransformation.TransformInt(SrcX, SrcY: Integer; out DstX, DstY: Integer);
  1032. var
  1033. X, Y: TFixed;
  1034. begin
  1035. TransformFixed(SrcX shl 16, SrcY shl 16, X, Y);
  1036. DstX := FixedRound(X);
  1037. DstY := FixedRound(Y);
  1038. end;
  1039. //------------------------------------------------------------------------------
  1040. //
  1041. // TNestedTransformation
  1042. //
  1043. //------------------------------------------------------------------------------
  1044. constructor TNestedTransformation.Create;
  1045. begin
  1046. FItems := TList.Create;
  1047. end;
  1048. destructor TNestedTransformation.Destroy;
  1049. begin
  1050. if Assigned(FItems) then
  1051. Clear;
  1052. FItems.Free;
  1053. inherited;
  1054. end;
  1055. function TNestedTransformation.Add(
  1056. ItemClass: TTransformationClass): TTransformation;
  1057. begin
  1058. Result := ItemClass.Create;
  1059. FItems.Add(Result);
  1060. end;
  1061. procedure TNestedTransformation.Clear;
  1062. begin
  1063. BeginUpdate;
  1064. try
  1065. while FItems.Count > 0 do
  1066. Delete(FItems.Count - 1);
  1067. finally
  1068. EndUpdate;
  1069. end;
  1070. end;
  1071. procedure TNestedTransformation.Delete(Index: Integer);
  1072. begin
  1073. TTransformation(FItems[Index]).Free;
  1074. FItems.Delete(Index);
  1075. end;
  1076. function TNestedTransformation.GetCount: Integer;
  1077. begin
  1078. Result := FItems.Count;
  1079. end;
  1080. function TNestedTransformation.GetItem(Index: Integer): TTransformation;
  1081. begin
  1082. Result := FItems[Index];
  1083. end;
  1084. function TNestedTransformation.Insert(Index: Integer;
  1085. ItemClass: TTransformationClass): TTransformation;
  1086. begin
  1087. BeginUpdate;
  1088. try
  1089. Result := Add(ItemClass);
  1090. finally
  1091. EndUpdate;
  1092. end;
  1093. end;
  1094. procedure TNestedTransformation.PrepareTransform;
  1095. var
  1096. Index: Integer;
  1097. begin
  1098. for Index := 0 to Count - 1 do
  1099. TTransformation(FItems[Index]).PrepareTransform;
  1100. end;
  1101. procedure TNestedTransformation.ReverseTransformFixed(DstX, DstY: TFixed;
  1102. out SrcX, SrcY: TFixed);
  1103. var
  1104. Index: Integer;
  1105. begin
  1106. for Index := 0 to Count - 1 do
  1107. begin
  1108. TTransformation(FItems[Index]).ReverseTransformFixed(DstX, DstY, SrcX,
  1109. SrcY);
  1110. DstX := SrcX;
  1111. DstY := SrcY;
  1112. end;
  1113. end;
  1114. procedure TNestedTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
  1115. out SrcX, SrcY: TFloat);
  1116. var
  1117. Index: Integer;
  1118. begin
  1119. for Index := 0 to Count - 1 do
  1120. begin
  1121. TTransformation(FItems[Index]).ReverseTransformFloat(DstX, DstY, SrcX,
  1122. SrcY);
  1123. DstX := SrcX;
  1124. DstY := SrcY;
  1125. end;
  1126. end;
  1127. procedure TNestedTransformation.SetItem(Index: Integer;
  1128. const Value: TTransformation);
  1129. begin
  1130. TCollectionItem(FItems[Index]).Assign(Value);
  1131. end;
  1132. procedure TNestedTransformation.TransformFixed(SrcX, SrcY: TFixed; out DstX,
  1133. DstY: TFixed);
  1134. var
  1135. Index: Integer;
  1136. begin
  1137. for Index := 0 to Count - 1 do
  1138. begin
  1139. TTransformation(FItems[Index]).TransformFixed(SrcX, SrcY, DstX, DstY);
  1140. SrcX := DstX;
  1141. SrcY := DstY;
  1142. end;
  1143. end;
  1144. procedure TNestedTransformation.TransformFloat(SrcX, SrcY: TFloat; out DstX,
  1145. DstY: TFloat);
  1146. var
  1147. Index: Integer;
  1148. begin
  1149. for Index := 0 to Count - 1 do
  1150. begin
  1151. TTransformation(FItems[Index]).TransformFloat(SrcX, SrcY, DstX, DstY);
  1152. SrcX := DstX;
  1153. SrcY := DstY;
  1154. end;
  1155. end;
  1156. //------------------------------------------------------------------------------
  1157. //
  1158. // T3x3Transformation
  1159. //
  1160. //------------------------------------------------------------------------------
  1161. procedure T3x3Transformation.PrepareTransform;
  1162. begin
  1163. FInverseMatrix := Matrix;
  1164. Invert(FInverseMatrix);
  1165. // calculate a fixed point (65536) factors
  1166. FInverseFixedMatrix := FixedMatrix(FInverseMatrix);
  1167. FFixedMatrix := FixedMatrix(Matrix);
  1168. TransformValid := True;
  1169. end;
  1170. procedure T3x3Transformation.ReverseTransformFixed(DstX, DstY: TFixed; out SrcX,
  1171. SrcY: TFixed);
  1172. begin
  1173. SrcX := FixedMul(DstX, FInverseFixedMatrix[0, 0]) +
  1174. FixedMul(DstY, FInverseFixedMatrix[1, 0]) + FInverseFixedMatrix[2, 0];
  1175. SrcY := FixedMul(DstX, FInverseFixedMatrix[0, 1]) +
  1176. FixedMul(DstY, FInverseFixedMatrix[1, 1]) + FInverseFixedMatrix[2, 1];
  1177. end;
  1178. procedure T3x3Transformation.ReverseTransformFloat(DstX, DstY: TFloat; out SrcX,
  1179. SrcY: TFloat);
  1180. begin
  1181. SrcX := DstX * FInverseMatrix[0, 0] + DstY * FInverseMatrix[1, 0] +
  1182. FInverseMatrix[2, 0];
  1183. SrcY := DstX * FInverseMatrix[0, 1] + DstY * FInverseMatrix[1, 1] +
  1184. FInverseMatrix[2, 1];
  1185. end;
  1186. procedure T3x3Transformation.TransformFixed(SrcX, SrcY: TFixed; out DstX,
  1187. DstY: TFixed);
  1188. begin
  1189. DstX := FixedMul(SrcX, FFixedMatrix[0, 0]) +
  1190. FixedMul(SrcY, FFixedMatrix[1, 0]) + FFixedMatrix[2, 0];
  1191. DstY := FixedMul(SrcX, FFixedMatrix[0, 1]) +
  1192. FixedMul(SrcY, FFixedMatrix[1, 1]) + FFixedMatrix[2, 1];
  1193. end;
  1194. procedure T3x3Transformation.TransformFloat(SrcX, SrcY: TFloat; out DstX,
  1195. DstY: TFloat);
  1196. begin
  1197. DstX := SrcX * Matrix[0, 0] + SrcY * Matrix[1, 0] + Matrix[2, 0];
  1198. DstY := SrcX * Matrix[0, 1] + SrcY * Matrix[1, 1] + Matrix[2, 1];
  1199. end;
  1200. //------------------------------------------------------------------------------
  1201. //
  1202. // TAffineTransformation
  1203. //
  1204. //------------------------------------------------------------------------------
  1205. constructor TAffineTransformation.Create;
  1206. begin
  1207. FStackLevel := 0;
  1208. FStack := nil;
  1209. Clear;
  1210. end;
  1211. procedure TAffineTransformation.Clear;
  1212. begin
  1213. FMatrix := IdentityMatrix;
  1214. Changed;
  1215. end;
  1216. procedure TAffineTransformation.Clear(BaseMatrix: TFloatMatrix);
  1217. begin
  1218. FMatrix := BaseMatrix;
  1219. Changed;
  1220. end;
  1221. function TAffineTransformation.GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect;
  1222. var
  1223. V1, V2, V3, V4: TVector3f;
  1224. begin
  1225. V1[0] := ASrcRect.Left; V1[1] := ASrcRect.Top; V1[2] := 1;
  1226. V2[0] := ASrcRect.Right; V2[1] := V1[1]; V2[2] := 1;
  1227. V3[0] := V1[0]; V3[1] := ASrcRect.Bottom; V3[2] := 1;
  1228. V4[0] := V2[0]; V4[1] := V3[1]; V4[2] := 1;
  1229. V1 := VectorTransform(Matrix, V1);
  1230. V2 := VectorTransform(Matrix, V2);
  1231. V3 := VectorTransform(Matrix, V3);
  1232. V4 := VectorTransform(Matrix, V4);
  1233. Result.Left := Min(Min(V1[0], V2[0]), Min(V3[0], V4[0]));
  1234. Result.Right := Max(Max(V1[0], V2[0]), Max(V3[0], V4[0]));
  1235. Result.Top := Min(Min(V1[1], V2[1]), Min(V3[1], V4[1]));
  1236. Result.Bottom := Max(Max(V1[1], V2[1]), Max(V3[1], V4[1]));
  1237. end;
  1238. procedure TAffineTransformation.Push;
  1239. begin
  1240. Inc(FStackLevel);
  1241. ReallocMem(FStack, FStackLevel * SizeOf(TFloatMatrix));
  1242. Move(FMatrix, FStack^[FStackLevel - 1], SizeOf(TFloatMatrix));
  1243. end;
  1244. procedure TAffineTransformation.Pop;
  1245. begin
  1246. if FStackLevel <= 0 then
  1247. raise Exception.Create(RStrStackEmpty);
  1248. Move(FStack^[FStackLevel - 1], FMatrix, SizeOf(TFloatMatrix));
  1249. Dec(FStackLevel);
  1250. Changed;
  1251. end;
  1252. procedure TAffineTransformation.Rotate(Alpha: TFloat);
  1253. var
  1254. S, C: TFloat;
  1255. M: TFloatMatrix;
  1256. begin
  1257. Alpha := DegToRad(Alpha);
  1258. GR32_Math.SinCos(Alpha, S, C);
  1259. M := IdentityMatrix;
  1260. M[0, 0] := C; M[1, 0] := S;
  1261. M[0, 1] := -S; M[1, 1] := C;
  1262. FMatrix := Mult(M, Matrix);
  1263. Changed;
  1264. end;
  1265. procedure TAffineTransformation.Rotate(Cx, Cy, Alpha: TFloat);
  1266. var
  1267. S, C: TFloat;
  1268. M: TFloatMatrix;
  1269. begin
  1270. if (Cx <> 0) or (Cy <> 0) then
  1271. Translate(-Cx, -Cy);
  1272. Alpha := DegToRad(Alpha);
  1273. GR32_Math.SinCos(Alpha, S, C);
  1274. M := IdentityMatrix;
  1275. M[0, 0] := C; M[1, 0] := S;
  1276. M[0, 1] := -S; M[1, 1] := C;
  1277. FMatrix := Mult(M, Matrix);
  1278. if (Cx <> 0) or (Cy <> 0) then
  1279. Translate(Cx, Cy);
  1280. Changed;
  1281. end;
  1282. procedure TAffineTransformation.Scale(Sx, Sy: TFloat);
  1283. var
  1284. M: TFloatMatrix;
  1285. begin
  1286. M := IdentityMatrix;
  1287. M[0, 0] := Sx;
  1288. M[1, 1] := Sy;
  1289. FMatrix := Mult(M, Matrix);
  1290. Changed;
  1291. end;
  1292. procedure TAffineTransformation.Scale(Value: TFloat);
  1293. var
  1294. M: TFloatMatrix;
  1295. begin
  1296. M := IdentityMatrix;
  1297. M[0, 0] := Value;
  1298. M[1, 1] := Value;
  1299. FMatrix := Mult(M, Matrix);
  1300. Changed;
  1301. end;
  1302. procedure TAffineTransformation.Skew(Fx, Fy: TFloat);
  1303. var
  1304. M: TFloatMatrix;
  1305. begin
  1306. M := IdentityMatrix;
  1307. M[1, 0] := Fx;
  1308. M[0, 1] := Fy;
  1309. FMatrix := Mult(M, Matrix);
  1310. Changed;
  1311. end;
  1312. procedure TAffineTransformation.Translate(Dx, Dy: TFloat);
  1313. var
  1314. M: TFloatMatrix;
  1315. begin
  1316. M := IdentityMatrix;
  1317. M[2, 0] := Dx;
  1318. M[2, 1] := Dy;
  1319. FMatrix := Mult(M, Matrix);
  1320. Changed;
  1321. end;
  1322. //------------------------------------------------------------------------------
  1323. //
  1324. // TProjectiveTransformation
  1325. //
  1326. //------------------------------------------------------------------------------
  1327. function TProjectiveTransformation.GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect;
  1328. begin
  1329. Result.Left := Min(Min(FQuadX[0], FQuadX[1]), Min(FQuadX[2], FQuadX[3]));
  1330. Result.Right := Max(Max(FQuadX[0], FQuadX[1]), Max(FQuadX[2], FQuadX[3]));
  1331. Result.Top := Min(Min(FQuadY[0], FQuadY[1]), Min(FQuadY[2], FQuadY[3]));
  1332. Result.Bottom := Max(Max(FQuadY[0], FQuadY[1]), Max(FQuadY[2], FQuadY[3]));
  1333. end;
  1334. function TProjectiveTransformation.GetX(Index: Integer): TFloat;
  1335. begin
  1336. Result := FQuadX[Index];
  1337. end;
  1338. function TProjectiveTransformation.GetY(Index: Integer): TFloat;
  1339. begin
  1340. Result := FQuadY[Index];
  1341. end;
  1342. procedure TProjectiveTransformation.PrepareTransform;
  1343. var
  1344. dx1, dx2, px, dy1, dy2, py: TFloat;
  1345. g, h, k: TFloat;
  1346. R: TFloatMatrix;
  1347. begin
  1348. px := FQuadX[0] - FQuadX[1] + FQuadX[2] - FQuadX[3];
  1349. py := FQuadY[0] - FQuadY[1] + FQuadY[2] - FQuadY[3];
  1350. if (px = 0) and (py = 0) then
  1351. begin
  1352. // affine mapping
  1353. FMatrix[0, 0] := FQuadX[1] - FQuadX[0];
  1354. FMatrix[1, 0] := FQuadX[2] - FQuadX[1];
  1355. FMatrix[2, 0] := FQuadX[0];
  1356. FMatrix[0, 1] := FQuadY[1] - FQuadY[0];
  1357. FMatrix[1, 1] := FQuadY[2] - FQuadY[1];
  1358. FMatrix[2, 1] := FQuadY[0];
  1359. FMatrix[0, 2] := 0;
  1360. FMatrix[1, 2] := 0;
  1361. FMatrix[2, 2] := 1;
  1362. end
  1363. else
  1364. begin
  1365. // projective mapping
  1366. dx1 := FQuadX[1] - FQuadX[2];
  1367. dx2 := FQuadX[3] - FQuadX[2];
  1368. dy1 := FQuadY[1] - FQuadY[2];
  1369. dy2 := FQuadY[3] - FQuadY[2];
  1370. k := dx1 * dy2 - dx2 * dy1;
  1371. if k <> 0 then
  1372. begin
  1373. k := 1 / k;
  1374. g := (px * dy2 - py * dx2) * k;
  1375. h := (dx1 * py - dy1 * px) * k;
  1376. FMatrix[0, 0] := FQuadX[1] - FQuadX[0] + g * FQuadX[1];
  1377. FMatrix[1, 0] := FQuadX[3] - FQuadX[0] + h * FQuadX[3];
  1378. FMatrix[2, 0] := FQuadX[0];
  1379. FMatrix[0, 1] := FQuadY[1] - FQuadY[0] + g * FQuadY[1];
  1380. FMatrix[1, 1] := FQuadY[3] - FQuadY[0] + h * FQuadY[3];
  1381. FMatrix[2, 1] := FQuadY[0];
  1382. FMatrix[0, 2] := g;
  1383. FMatrix[1, 2] := h;
  1384. FMatrix[2, 2] := 1;
  1385. end
  1386. else
  1387. begin
  1388. FillChar(FMatrix, SizeOf(FMatrix), 0);
  1389. end;
  1390. end;
  1391. // denormalize texture space (u, v)
  1392. R := IdentityMatrix;
  1393. R[0, 0] := 1 / (SrcRect.Right - SrcRect.Left);
  1394. R[1, 1] := 1 / (SrcRect.Bottom - SrcRect.Top);
  1395. FMatrix := Mult(FMatrix, R);
  1396. R := IdentityMatrix;
  1397. R[2, 0] := -SrcRect.Left;
  1398. R[2, 1] := -SrcRect.Top;
  1399. FMatrix := Mult(FMatrix, R);
  1400. inherited;
  1401. end;
  1402. procedure TProjectiveTransformation.SetX(Index: Integer; const Value: TFloat);
  1403. begin
  1404. FQuadX[Index] := Value;
  1405. Changed;
  1406. end;
  1407. procedure TProjectiveTransformation.SetY(Index: Integer; const Value: TFloat);
  1408. begin
  1409. FQuadY[Index] := Value;
  1410. Changed;
  1411. end;
  1412. procedure TProjectiveTransformation.ReverseTransformFixed(DstX, DstY: TFixed;
  1413. out SrcX, SrcY: TFixed);
  1414. var
  1415. Z: TFixed;
  1416. Zf: TFloat;
  1417. begin
  1418. Z := FixedMul(FInverseFixedMatrix[0, 2], DstX) +
  1419. FixedMul(FInverseFixedMatrix[1, 2], DstY) + FInverseFixedMatrix[2, 2];
  1420. if Z = 0 then
  1421. Exit;
  1422. {$IFDEF UseInlining}
  1423. SrcX := FixedMul(DstX, FInverseFixedMatrix[0, 0]) +
  1424. FixedMul(DstY, FInverseFixedMatrix[1, 0]) + FInverseFixedMatrix[2, 0];
  1425. SrcY := FixedMul(DstX, FInverseFixedMatrix[0,1]) +
  1426. FixedMul(DstY, FInverseFixedMatrix[1, 1]) + FInverseFixedMatrix[2, 1];
  1427. {$ELSE}
  1428. inherited;
  1429. {$ENDIF}
  1430. if Z <> FixedOne then
  1431. begin
  1432. Zf := FixedOne / Z;
  1433. SrcX := Round(SrcX * Zf);
  1434. SrcY := Round(SrcY * Zf);
  1435. end;
  1436. end;
  1437. procedure TProjectiveTransformation.ReverseTransformFloat(
  1438. DstX, DstY: TFloat;
  1439. out SrcX, SrcY: TFloat);
  1440. var
  1441. Z: TFloat;
  1442. begin
  1443. Z := FInverseMatrix[0, 2] * DstX + FInverseMatrix[1, 2] * DstY +
  1444. FInverseMatrix[2, 2];
  1445. if Z = 0 then
  1446. Exit;
  1447. {$IFDEF UseInlining}
  1448. SrcX := DstX * FInverseMatrix[0, 0] + DstY * FInverseMatrix[1, 0] +
  1449. FInverseMatrix[2, 0];
  1450. SrcY := DstX * FInverseMatrix[0, 1] + DstY * FInverseMatrix[1, 1] +
  1451. FInverseMatrix[2, 1];
  1452. {$ELSE}
  1453. inherited;
  1454. {$ENDIF}
  1455. if Z <> 1 then
  1456. begin
  1457. Z := 1 / Z;
  1458. SrcX := SrcX * Z;
  1459. SrcY := SrcY * Z;
  1460. end;
  1461. end;
  1462. procedure TProjectiveTransformation.TransformFixed(SrcX, SrcY: TFixed;
  1463. out DstX, DstY: TFixed);
  1464. var
  1465. Z: TFixed;
  1466. Zf: TFloat;
  1467. begin
  1468. Z := FixedMul(FFixedMatrix[0, 2], SrcX) +
  1469. FixedMul(FFixedMatrix[1, 2], SrcY) + FFixedMatrix[2, 2];
  1470. if Z = 0 then
  1471. Exit;
  1472. {$IFDEF UseInlining}
  1473. DstX := FixedMul(SrcX, FFixedMatrix[0, 0]) +
  1474. FixedMul(SrcY, FFixedMatrix[1, 0]) + FFixedMatrix[2, 0];
  1475. DstY := FixedMul(SrcX, FFixedMatrix[0, 1]) +
  1476. FixedMul(SrcY, FFixedMatrix[1, 1]) + FFixedMatrix[2, 1];
  1477. {$ELSE}
  1478. inherited;
  1479. {$ENDIF}
  1480. if Z <> FixedOne then
  1481. begin
  1482. Zf := FixedOne / Z;
  1483. DstX := Round(DstX * Zf);
  1484. DstY := Round(DstY * Zf);
  1485. end;
  1486. end;
  1487. procedure TProjectiveTransformation.TransformFloat(SrcX, SrcY: TFloat;
  1488. out DstX, DstY: TFloat);
  1489. var
  1490. Z: TFloat;
  1491. begin
  1492. Z := FMatrix[0, 2] * SrcX + FMatrix[1, 2] * SrcY + FMatrix[2, 2];
  1493. if Z = 0 then Exit;
  1494. {$IFDEF UseInlining}
  1495. DstX := SrcX * Matrix[0, 0] + SrcY * Matrix[1, 0] + Matrix[2, 0];
  1496. DstY := SrcX * Matrix[0, 1] + SrcY * Matrix[1, 1] + Matrix[2, 1];
  1497. {$ELSE}
  1498. inherited;
  1499. {$ENDIF}
  1500. if Z <> 1 then
  1501. begin
  1502. Z := 1 / Z;
  1503. DstX := DstX * Z;
  1504. DstY := DstY * Z;
  1505. end;
  1506. end;
  1507. //------------------------------------------------------------------------------
  1508. //
  1509. // TProjectiveTransformationEx
  1510. //
  1511. //------------------------------------------------------------------------------
  1512. // Based on amBitmapEditorToolForwardProjectiveTransform by Anders Melander
  1513. //------------------------------------------------------------------------------
  1514. {$ifndef FPC}
  1515. function TProjectiveTransformationEx.GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect;
  1516. var
  1517. i: integer;
  1518. Bounds: TFloatQuadrilateral;
  1519. begin
  1520. if (FExtrapolate) then
  1521. Exit(ASrcRect);
  1522. // Transform the coords of the source rect to find the coords of
  1523. // the corresponding target quad. Then return the boinding box of
  1524. // this quad.
  1525. for i := 0 to High(Bounds) do
  1526. ReverseTransformFloat(FSourceQuad[i].X, FSourceQuad[i].Y, Bounds[i].X, Bounds[i].Y);
  1527. Result.Left := Min(Min(Bounds[0].X, Bounds[1].X), Min(Bounds[2].X, Bounds[3].X));
  1528. Result.Right := Max(Max(Bounds[0].X, Bounds[1].X), Max(Bounds[2].X, Bounds[3].X));
  1529. Result.Top := Min(Min(Bounds[0].Y, Bounds[1].Y), Min(Bounds[2].Y, Bounds[3].Y));
  1530. Result.Bottom := Max(Max(Bounds[0].Y, Bounds[1].Y), Max(Bounds[2].Y, Bounds[3].Y));
  1531. (* Naive; Does not take projection to DestQuad into account.
  1532. Result.Left := Min(Min(FDestQuad[0].X, FDestQuad[1].X), Min(FDestQuad[2].X, FDestQuad[3].X));
  1533. Result.Right := Max(Max(FDestQuad[0].X, FDestQuad[1].X), Max(FDestQuad[2].X, FDestQuad[3].X));
  1534. Result.Top := Min(Min(FDestQuad[0].Y, FDestQuad[1].Y), Min(FDestQuad[2].Y, FDestQuad[3].Y));
  1535. Result.Bottom := Max(Max(FDestQuad[0].Y, FDestQuad[1].Y), Max(FDestQuad[2].Y, FDestQuad[3].Y));
  1536. *)
  1537. end;
  1538. function TProjectiveTransformationEx.GetSource(Index: Integer): TFloatPoint;
  1539. begin
  1540. Result := FSourceQuad[Index];
  1541. end;
  1542. function TProjectiveTransformationEx.GetSourceX(Index: Integer): TFloat;
  1543. begin
  1544. Result := FSourceQuad[Index].X;
  1545. end;
  1546. function TProjectiveTransformationEx.GetSourceY(Index: Integer): TFloat;
  1547. begin
  1548. Result := FSourceQuad[Index].Y;
  1549. end;
  1550. function TProjectiveTransformationEx.GetDest(Index: Integer): TFloatPoint;
  1551. begin
  1552. Result := FDestQuad[Index];
  1553. end;
  1554. function TProjectiveTransformationEx.GetDestX(Index: Integer): TFloat;
  1555. begin
  1556. Result := FDestQuad[Index].X;
  1557. end;
  1558. function TProjectiveTransformationEx.GetDestY(Index: Integer): TFloat;
  1559. begin
  1560. Result := FDestQuad[Index].Y;
  1561. end;
  1562. procedure TProjectiveTransformationEx.SetSource(Index: Integer; const Value: TFloatPoint);
  1563. begin
  1564. FSourceQuad[Index] := Value;
  1565. Changed;
  1566. end;
  1567. procedure TProjectiveTransformationEx.SetSourceQuad(const Value: TFloatQuadrilateral);
  1568. begin
  1569. FSourceQuad := Value;
  1570. Changed;
  1571. end;
  1572. procedure TProjectiveTransformationEx.SetSourceX(Index: Integer; const Value: TFloat);
  1573. begin
  1574. FSourceQuad[Index].Y := Value;
  1575. Changed;
  1576. end;
  1577. procedure TProjectiveTransformationEx.SetSourceY(Index: Integer; const Value: TFloat);
  1578. begin
  1579. FSourceQuad[Index].X := Value;
  1580. Changed;
  1581. end;
  1582. procedure TProjectiveTransformationEx.SetDest(Index: Integer; const Value: TFloatPoint);
  1583. begin
  1584. FDestQuad[Index] := Value;
  1585. Changed;
  1586. end;
  1587. procedure TProjectiveTransformationEx.SetDestQuad(const Value: TFloatQuadrilateral);
  1588. begin
  1589. FDestQuad := Value;
  1590. Changed;
  1591. end;
  1592. procedure TProjectiveTransformationEx.SetDestX(Index: Integer; const Value: TFloat);
  1593. begin
  1594. FDestQuad[Index].X := Value;
  1595. Changed;
  1596. end;
  1597. procedure TProjectiveTransformationEx.SetDestY(Index: Integer; const Value: TFloat);
  1598. begin
  1599. FDestQuad[Index].Y := Value;
  1600. Changed;
  1601. end;
  1602. procedure TProjectiveTransformationEx.PrepareTransform;
  1603. //------------------------------------------------------------------------------
  1604. // From "Fundamentals of Texture Mapping and Image Warping" by Paul S. Heckbert:
  1605. //------------------------------------------------------------------------------
  1606. //
  1607. // The general form of a projective mapping is a rational linear mapping:
  1608. //
  1609. // au + bv + c du + ev + f
  1610. // x = ------------- , y = ------------- [1]
  1611. // gu + hv + i gu + hv + i
  1612. //
  1613. // Manipulation of projective mappings is much easier in the homogeneous matrix notation:
  1614. //
  1615. // Pd = Ps * Msd
  1616. //
  1617. // ┌ ┐ ┌ ┐┌ ┐
  1618. // │ x' │ │ a d g ││ u' │
  1619. // = │ y' │ = │ b e h ││ v' │
  1620. // │ w │ │ c f i ││ q │
  1621. // └ ┘ └ ┘└ ┘
  1622. //
  1623. // T T T T
  1624. // where (x,y) = (x'/ w, y'/w) for w ≠ 0, and (u,v) = (u'/q, v'/q) for q ≠ 0.
  1625. //
  1626. // Although there are 9 coefficients in the matrix above, these mappings are homogeneous, so
  1627. // any nonzero scalar multiple of these matrices gives an equivalent mapping. Hence there are only
  1628. // 8 degrees of freedom in a 2-D projective mapping. We can assume without loss of generality that
  1629. // i=1 except in the special case that source point (0, 0)T maps to a point at infinity. A projective
  1630. // mapping is affine when g=h=0.
  1631. //
  1632. // ...
  1633. //
  1634. // Projective mappings may be composed by concatenating their matrices.
  1635. //
  1636. // Another remarkable property is that the inverse of a projective mapping is a projective mapping.
  1637. // This is intuitively explained by reversing the plane-to-plane mapping by which a projective mapping
  1638. // is defined. The matrix for the inverse mapping is the inverse or adjoint of the forward mapping. (The
  1639. // adjoint of a matrix is the transpose of the matrix of cofactors; M^-1 = adj(M)/det(M)).
  1640. // In homogeneous algebra, the adjoint matrix can be used in place of the inverse matrix whenever an
  1641. // inverse transform is needed, since the two are scalar multiples of each other, and the adjoint always
  1642. // exists, while the inverse does not if the matrix is singular. The inverse transformation is thus:
  1643. //
  1644. // Ps = Msd * Pd
  1645. //
  1646. // ┌ ┐ ┌ ┐┌ ┐
  1647. // │ u' │ │ A D G ││ x' │
  1648. // = │ v' │ = │ B E H ││ y' │
  1649. // │ q │ │ C F I ││ w │
  1650. // └ ┘ └ ┘└ ┘
  1651. //
  1652. // ┌ ┐┌ ┐
  1653. // │ ei-fh ch-bi bf-ce ││ x' │
  1654. // = │ fg-di ai-cg cd-af ││ y' │
  1655. // │ dh-eg bg-ah ae-bd ││ w │
  1656. // └ ┘└ ┘
  1657. // T T
  1658. // When mapping a point by the inverse transform we compute (u, v) from (x, y). If w ≠ 0 and
  1659. // q ≠ 0 then we can choose w = 1 and calculate:
  1660. //
  1661. // Ax + By + C Dx + Ey + F
  1662. // u = ------------- , y = ------------- [2]
  1663. // Gx + Hy + I Gx + Hy + I
  1664. //
  1665. // ...
  1666. //
  1667. // In an interactive image warper one might specify the four corners of source and destination quadrilaterals
  1668. // with a tablet or mouse, and wish to warp one area to the other. This sort of task is an ideal
  1669. // application of projective mappings, but how do we find the mapping matrix?
  1670. //
  1671. // A projective mapping has 8 degrees of freedom which can be determined from the source and
  1672. // destination coordinates of the four corners of a quadrilateral. Let the correspondence map (uk, vk)^T
  1673. // to (xk, yk)^T for vertices numbered cyclically k = 0,1,2,3. All coordinates are assumed to be real
  1674. // (finite). To compute the forward mapping matrix Msd, assuming that i= 1, we have eight equations
  1675. // in the eight unknowns a-h:
  1676. //
  1677. // auk + bvk + c
  1678. // xk = --------------- => uka + vkb + c - ukxkg - vkxkh = xk
  1679. // guk + hvk + 1
  1680. //
  1681. // duk + evk + f
  1682. // yk = --------------- => ukd + vke + f - ukykg - vkykh = yk
  1683. // guk + hvk + 1
  1684. //
  1685. // for k = 0,1,2,3. This can be rewritten as an 8 × 8 system:
  1686. //
  1687. // ┌ ┐┌ ┐ ┌ ┐
  1688. // │ u0 v0 1 0 0 0 -u0x0 -v0x0 ││ a │ │ x0 │
  1689. // │ u1 v1 1 0 0 0 -u1x1 -v1x1 ││ b │ │ x1 │
  1690. // │ u2 v2 1 0 0 0 -u2x2 -v2x2 ││ c │ │ x2 │
  1691. // │ u3 v3 1 0 0 0 -u3x3 -v3x3 ││ d │ = │ x3 │
  1692. // │ 0 0 0 u0 v0 1 -u0y0 -v0y0 ││ e │ │ y0 │
  1693. // │ 0 0 0 u1 v1 1 -u1y1 -v1y1 ││ f │ │ y1 │
  1694. // │ 0 0 0 u2 v2 1 -u2y2 -v2y2 ││ g │ │ y2 │
  1695. // │ 0 0 0 u3 v3 1 -u3y3 -v3y3 ││ h │ │ y3 │
  1696. // └ ┘└ ┘ └ ┘
  1697. //
  1698. // This linear system can be solved using Gaussian elimination or other methods for the forward mapping
  1699. // coefficients a-h. If the inverse mapping is desired instead, then either we compute the adjoint
  1700. // of Msd or we follow the same procedure, starting from equation [2] instead of [1], and solve an
  1701. // 8 × 8 system for coefficients A-H.
  1702. //
  1703. // In speed-critical special cases, there are more efficient formulas for computing the mapping
  1704. // matrix. The formula above handles the case where the polygon is a general quadrilateral in both
  1705. // source and destination spaces. We will consider three additional cases: square-to-quadrilateral,
  1706. // quadrilateral-to-square, and (again) the general quadrilateral-to-quadrilateral mapping.
  1707. //
  1708. // Case 1. The system is easily solved symbolically in the special case where the uv quadrilateral
  1709. // is a unit square. If the vertex correspondence is as follows:
  1710. //
  1711. // x y u v
  1712. // -------------
  1713. // x0 y0 0 0
  1714. // x1 y1 1 0
  1715. // x2 y2 1 1
  1716. // x3 y3 0 1
  1717. //
  1718. // then the eight equations reduce to
  1719. //
  1720. // c = x0
  1721. // a + c - gx1 = x1
  1722. // a + c - gx2 - hx2 = x2
  1723. // b + c - hx3 = x3
  1724. // f = y0
  1725. // d + f - gy1 = y1
  1726. // d + e + f - gy2 - hy2 = y2
  1727. // e + f - hy3 = y3
  1728. //
  1729. // If we define
  1730. //
  1731. // ∆x1 = x1 - x2, ∆x2 = x3 - x2, ∑x = x0 - x1 + x2 - x3 [a.1]
  1732. // ∆y1 = y1 - y2, ∆y2 = y3 - y2, ∑y = y0 - y1 + y2 - y3 [a.2]
  1733. //
  1734. // then the solution splits into two sub-cases:
  1735. //
  1736. // (a) ∑x = 0 and ∑y = 0. This implies that the xy polygon is a parallelogram, so the mapping is
  1737. // affine, and a = x1 - x0, b = x2 - x1, c = x0, d = y1 - y0, e = y2 - y1, f = y0, g = 0, h = 0. [b]
  1738. //
  1739. // (b) ∑x ≠ 0 or ∑y ≠ 0 gives a projective mapping:
  1740. // │ ∑x ∆x2 │ │ ∆x1 ∆x2 │
  1741. // g = │ │ / │ │ [c.1]
  1742. // │ ∑y ∆y2 │ │ ∆y1 ∆y2 │
  1743. //
  1744. //
  1745. // │ ∆x1 ∑x │ │ ∆x1 ∆x2 │
  1746. // h = │ │ / │ │ [c.2]
  1747. // │ ∆y1 ∑y │ │ ∆y1 ∆y2 │
  1748. //
  1749. // a = x1 - x0 + gx1 [c.3]
  1750. // b = x3 - x0 + hx3
  1751. // c = x0
  1752. // d = y1 - y0 + gy1
  1753. // e = y3 - y0 + hy3
  1754. // f = y0
  1755. //
  1756. // This computation is much faster than a straightforward 8 × 8 system solver. The mapping above is
  1757. // easily generalized to map a rectangle to a quadrilateral by pre-multiplying with a scale and translation
  1758. // matrix.
  1759. //
  1760. // Case 2. The inverse mapping, a quadrilateral to a square, can also be optimized. It turns out
  1761. // that the most efficient algorithm for computing this is not purely symbolic, as in the previous case,
  1762. // but numerical. We use the square-to-quadrilateral formulas just described to find the inverse of the
  1763. // desired mapping, and then take its adjoint to compute the quadrilateral-to-square mapping.
  1764. //
  1765. // Case 3. Since we can compute quadrilateral-to-square and square-to-quadrilateral mappings
  1766. // quickly, the two mappings can easily be composed to yield a general quadrilateral-to-
  1767. // mapping. This solution method is faster than a general 8 × 8 system solver.
  1768. //
  1769. procedure CreateProjectiveMapping(const Quad: TFloatQuadrilateral; var Matrix: TFloatMatrix);
  1770. var
  1771. ∑x, ∑y: TFloat;
  1772. ∆x1, ∆x2, ∆y1, ∆y2: TFloat;
  1773. g, h, k: TFloat;
  1774. begin
  1775. ∑x := Quad[0].X - Quad[1].X + Quad[2].X - Quad[3].X; // See [a]
  1776. ∑y := Quad[0].Y - Quad[1].Y + Quad[2].Y - Quad[3].Y;
  1777. if (IsZero(∑x)) and (IsZero(∑y)) then // See [b]
  1778. begin
  1779. // Quadrilateral is a parallelogram - Mapping is affine
  1780. // ┌ ┐
  1781. // │ a d 0 │
  1782. // │ b e 0 │
  1783. // │ c f 1 │
  1784. // └ ┘
  1785. Matrix[0, 0] := Quad[1].X - Quad[0].X; // a
  1786. Matrix[1, 0] := Quad[2].X - Quad[1].X; // b
  1787. Matrix[2, 0] := Quad[0].X; // c
  1788. Matrix[0, 1] := Quad[1].Y - Quad[0].Y; // d
  1789. Matrix[1, 1] := Quad[2].Y - Quad[1].Y; // e
  1790. Matrix[2, 1] := Quad[0].Y; // f
  1791. Matrix[0, 2] := 0; // g
  1792. Matrix[1, 2] := 0; // h
  1793. Matrix[2, 2] := 1; // i
  1794. end else
  1795. begin
  1796. // Projective mapping
  1797. // ┌ ┐
  1798. // │ a d g │
  1799. // │ b e h │
  1800. // │ c f 1 │
  1801. // └ ┘
  1802. ∆x1 := Quad[1].X - Quad[2].X; // See [a]
  1803. ∆x2 := Quad[3].X - Quad[2].X;
  1804. ∆y1 := Quad[1].Y - Quad[2].Y;
  1805. ∆y2 := Quad[3].Y - Quad[2].Y;
  1806. k := ∆x1 * ∆y2 - ∆x2 * ∆y1;
  1807. if (not IsZero(k)) then
  1808. begin
  1809. k := 1 / k; // Avoid (one) costly divisions below
  1810. g := (∑x * ∆y2 - ∑y * ∆x2) * k; // See [c]
  1811. h := (∆x1 * ∑y - ∆y1 * ∑x) * k;
  1812. Matrix[0, 0] := Quad[1].X - Quad[0].X + g * Quad[1].X; // a
  1813. Matrix[1, 0] := Quad[3].X - Quad[0].X + h * Quad[3].X; // b
  1814. Matrix[2, 0] := Quad[0].X; // c
  1815. Matrix[0, 1] := Quad[1].Y - Quad[0].Y + g * Quad[1].Y; // d
  1816. Matrix[1, 1] := Quad[3].Y - Quad[0].Y + h * Quad[3].Y; // e
  1817. Matrix[2, 1] := Quad[0].Y; // f
  1818. Matrix[0, 2] := g; // g
  1819. Matrix[1, 2] := h; // h
  1820. Matrix[2, 2] := 1; // i
  1821. end else
  1822. Matrix := Default(TFloatMatrix);
  1823. end;
  1824. end;
  1825. var
  1826. SourceMatrix: TFloatMatrix;
  1827. DestMatrix: TFloatMatrix;
  1828. // R: TFloatMatrix;
  1829. begin
  1830. CreateProjectiveMapping(FSourceQuad, SourceMatrix);
  1831. CreateProjectiveMapping(FDestQuad, DestMatrix);
  1832. Invert(DestMatrix);
  1833. FMatrix := Mult(SourceMatrix, DestMatrix);
  1834. (*
  1835. // Denormalize texture space (u, v)
  1836. // Scale
  1837. R := IdentityMatrix;
  1838. R[0, 0] := 1 / (SrcRect.Right - SrcRect.Left);
  1839. R[1, 1] := 1 / (SrcRect.Bottom - SrcRect.Top);
  1840. FMatrix := Mult(FMatrix, R);
  1841. // Translate
  1842. R := IdentityMatrix;
  1843. R[2, 0] := -SrcRect.Left;
  1844. R[2, 1] := -SrcRect.Top;
  1845. FMatrix := Mult(FMatrix, R);
  1846. *)
  1847. inherited;
  1848. end;
  1849. procedure TProjectiveTransformationEx.ReverseTransformFixed(DstX, DstY: TFixed; out SrcX, SrcY: TFixed);
  1850. var
  1851. Z: TFixed;
  1852. Zf: TFloat;
  1853. begin
  1854. Z := FixedMul(FInverseFixedMatrix[0, 2], DstX) +
  1855. FixedMul(FInverseFixedMatrix[1, 2], DstY) +
  1856. FInverseFixedMatrix[2, 2];
  1857. if Z = 0 then
  1858. Exit;
  1859. {$IFDEF UseInlining}
  1860. SrcX := FixedMul(FInverseFixedMatrix[0, 0], DstX) +
  1861. FixedMul(FInverseFixedMatrix[1, 0], DstY) +
  1862. FInverseFixedMatrix[2, 0];
  1863. SrcY := FixedMul(FInverseFixedMatrix[0, 1], DstX) +
  1864. FixedMul(FInverseFixedMatrix[1, 1], DstY) +
  1865. FInverseFixedMatrix[2, 1];
  1866. {$ELSE}
  1867. inherited;
  1868. {$ENDIF}
  1869. if Z <> FixedOne then
  1870. begin
  1871. Zf := FixedOne / Z;
  1872. SrcX := Round(SrcX * Zf);
  1873. SrcY := Round(SrcY * Zf);
  1874. end;
  1875. end;
  1876. procedure TProjectiveTransformationEx.ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat);
  1877. var
  1878. Z: TFloat;
  1879. begin
  1880. Z := FInverseMatrix[0, 2] * DstX +
  1881. FInverseMatrix[1, 2] * DstY +
  1882. FInverseMatrix[2, 2];
  1883. if IsZero(Z) then
  1884. Exit;
  1885. {$IFDEF UseInlining}
  1886. SrcX := FInverseMatrix[0, 0] * DstX +
  1887. FInverseMatrix[1, 0] * DstY +
  1888. FInverseMatrix[2, 0];
  1889. SrcY := FInverseMatrix[0, 1] * DstX +
  1890. FInverseMatrix[1, 1] * DstY +
  1891. FInverseMatrix[2, 1];
  1892. {$ELSE}
  1893. inherited;
  1894. {$ENDIF}
  1895. if Z <> 1 then
  1896. begin
  1897. Z := 1 / Z;
  1898. SrcX := SrcX * Z;
  1899. SrcY := SrcY * Z;
  1900. end;
  1901. end;
  1902. procedure TProjectiveTransformationEx.TransformFixed(SrcX, SrcY: TFixed; out DstX, DstY: TFixed);
  1903. var
  1904. Z: TFixed;
  1905. Zf: TFloat;
  1906. begin
  1907. Z := FixedMul(FFixedMatrix[0, 2], SrcX) +
  1908. FixedMul(FFixedMatrix[1, 2], SrcY) +
  1909. FFixedMatrix[2, 2];
  1910. if Z = 0 then
  1911. Exit;
  1912. {$IFDEF UseInlining}
  1913. DstX := FixedMul(FFixedMatrix[0, 0], SrcX) +
  1914. FixedMul(FFixedMatrix[1, 0], SrcY) +
  1915. FFixedMatrix[2, 0];
  1916. DstY := FixedMul(FFixedMatrix[0, 1], SrcX) +
  1917. FixedMul(FFixedMatrix[1, 1], SrcY) +
  1918. FFixedMatrix[2, 1];
  1919. {$ELSE}
  1920. inherited;
  1921. {$ENDIF}
  1922. if Z <> FixedOne then
  1923. begin
  1924. Zf := FixedOne / Z;
  1925. DstX := Round(DstX * Zf);
  1926. DstY := Round(DstY * Zf);
  1927. end;
  1928. end;
  1929. procedure TProjectiveTransformationEx.TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat);
  1930. var
  1931. Z: TFloat;
  1932. begin
  1933. Z := FMatrix[0, 2] * SrcX +
  1934. FMatrix[1, 2] * SrcY +
  1935. FMatrix[2, 2];
  1936. if IsZero(Z) then
  1937. Exit;
  1938. {$IFDEF UseInlining}
  1939. DstX := FMatrix[0, 0] * SrcX +
  1940. FMatrix[1, 0] * SrcY +
  1941. FMatrix[2, 0];
  1942. DstY := FMatrix[0, 1] * SrcX +
  1943. FMatrix[1, 1] * SrcY +
  1944. FMatrix[2, 1];
  1945. {$ELSE}
  1946. inherited;
  1947. {$ENDIF}
  1948. if Z <> 1 then
  1949. begin
  1950. Z := 1 / Z;
  1951. DstX := DstX * Z;
  1952. DstY := DstY * Z;
  1953. end;
  1954. end;
  1955. {$endif FPC}
  1956. //------------------------------------------------------------------------------
  1957. //
  1958. // TTwirlTransformation
  1959. //
  1960. //------------------------------------------------------------------------------
  1961. constructor TTwirlTransformation.Create;
  1962. begin
  1963. FTwirl := 0.03;
  1964. end;
  1965. function TTwirlTransformation.GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect;
  1966. var
  1967. Cx, Cy, R: TFloat;
  1968. const
  1969. CPiHalf: TFloat = 0.5 * Pi;
  1970. begin
  1971. Cx := (ASrcRect.Left + ASrcRect.Right) * 0.5;
  1972. Cy := (ASrcRect.Top + ASrcRect.Bottom) * 0.5;
  1973. R := Max(Cx - ASrcRect.Left, Cy - ASrcRect.Top);
  1974. Result.Left := Cx - R * CPiHalf;
  1975. Result.Right := Cx + R * CPiHalf;
  1976. Result.Top := Cy - R * CPiHalf;
  1977. Result.Bottom := Cy + R * CPiHalf;
  1978. end;
  1979. procedure TTwirlTransformation.PrepareTransform;
  1980. begin
  1981. with FSrcRect do
  1982. begin
  1983. Frx := (Right - Left) * 0.5;
  1984. Fry := (Bottom - Top) * 0.5;
  1985. end;
  1986. TransformValid := True;
  1987. end;
  1988. procedure TTwirlTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
  1989. out SrcX, SrcY: TFloat);
  1990. var
  1991. xf, yf, r, t: Single;
  1992. begin
  1993. xf := DstX - Frx;
  1994. yf := DstY - Fry;
  1995. r := GR32_Math.Hypot(xf, yf);
  1996. t := ArcTan2(yf, xf) + r * FTwirl;
  1997. GR32_Math.SinCos(t, yf, xf);
  1998. SrcX := Frx + r * xf;
  1999. SrcY := Fry + r * yf;
  2000. end;
  2001. procedure TTwirlTransformation.SetTwirl(const Value: TFloat);
  2002. begin
  2003. FTwirl := Value;
  2004. Changed;
  2005. end;
  2006. //------------------------------------------------------------------------------
  2007. //
  2008. // TBloatTransformation
  2009. //
  2010. //------------------------------------------------------------------------------
  2011. constructor TBloatTransformation.Create;
  2012. begin
  2013. FBloatPower := 0.3;
  2014. end;
  2015. procedure TBloatTransformation.PrepareTransform;
  2016. begin
  2017. FPiW := (Pi / (FSrcRect.Right - FSrcRect.Left));
  2018. FPiH := (Pi / (FSrcRect.Bottom - FSrcRect.Top));
  2019. FBP := FBloatPower * Max(FSrcRect.Right - FSrcRect.Left, FSrcRect.Bottom - FSrcRect.Top);
  2020. TransformValid := True;
  2021. end;
  2022. procedure TBloatTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
  2023. out SrcX, SrcY: TFloat);
  2024. var
  2025. SinY, CosY, SinX, CosX, t: Single;
  2026. begin
  2027. GR32_Math.SinCos(FPiH * DstY, SinY, CosY);
  2028. GR32_Math.SinCos(FPiW * DstX, SinX, CosX);
  2029. t := FBP * SinY * SinX;
  2030. SrcX := DstX + t * CosX;
  2031. SrcY := DstY + t * CosY;
  2032. end;
  2033. procedure TBloatTransformation.TransformFloat(DstX, DstY: TFloat;
  2034. out SrcX, SrcY: TFloat);
  2035. var
  2036. SinY, CosY, SinX, CosX, t: Single;
  2037. begin
  2038. GR32_Math.SinCos(-FPiH * DstY, SinY, CosY);
  2039. GR32_Math.SinCos(-FPiW * DstX, SinX, CosX);
  2040. t := FBP * SinY * SinX;
  2041. SrcX := DstX + t * CosX;
  2042. SrcY := DstY + t * CosY;
  2043. end;
  2044. procedure TBloatTransformation.SetBloatPower(const Value: TFloat);
  2045. begin
  2046. FBloatPower := Value;
  2047. Changed;
  2048. end;
  2049. //------------------------------------------------------------------------------
  2050. //
  2051. // TFishEyeTransformation
  2052. //
  2053. //------------------------------------------------------------------------------
  2054. procedure TFishEyeTransformation.PrepareTransform;
  2055. begin
  2056. with FSrcRect do
  2057. begin
  2058. Frx := (Right - Left) * 0.5;
  2059. Fry := (Bottom - Top) * 0.5;
  2060. if Frx <= Fry then
  2061. begin
  2062. FMinR := Frx;
  2063. Sx := 1;
  2064. Sy:= Frx / Fry;
  2065. end
  2066. else
  2067. begin
  2068. FMinR := Fry;
  2069. Sx:= Fry / Frx;
  2070. Sy := 1;
  2071. end;
  2072. Fsr := 1 / FMinR;
  2073. Faw := ArcSin(Constrain(FMinR * Fsr, -1, 1));
  2074. if Faw <> 0 then
  2075. Faw := 1 / Faw;
  2076. Faw := Faw * FMinR
  2077. end;
  2078. TransformValid := True;
  2079. end;
  2080. procedure TFishEyeTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
  2081. out SrcX, SrcY: TFloat);
  2082. var
  2083. d, Xrx, Yry: TFloat;
  2084. begin
  2085. Yry := (DstY - Fry) * sy;
  2086. Xrx := (DstX - Frx) * sx;
  2087. d := GR32_Math.Hypot(Xrx, Yry);
  2088. if (d < FMinR) and (d > 0) then
  2089. begin
  2090. d := ArcSin(d * Fsr) * Faw / d;
  2091. SrcX := Frx + Xrx * d;
  2092. SrcY := Fry + Yry * d;
  2093. end
  2094. else
  2095. begin
  2096. SrcX := DstX;
  2097. SrcY := DstY;
  2098. end;
  2099. end;
  2100. //------------------------------------------------------------------------------
  2101. //
  2102. // TPolarTransformation
  2103. //
  2104. //------------------------------------------------------------------------------
  2105. procedure TPolarTransformation.PrepareTransform;
  2106. begin
  2107. Sx := SrcRect.Right - SrcRect.Left;
  2108. Sy := SrcRect.Bottom - SrcRect.Top;
  2109. Cx := (DstRect.Left + DstRect.Right) * 0.5;
  2110. Cy := (DstRect.Top + DstRect.Bottom) * 0.5;
  2111. Dx := DstRect.Right - Cx;
  2112. Dy := DstRect.Bottom - Cy;
  2113. Rt := (1 / (PI * 2)) * Sx;
  2114. Rt2 := Sx;
  2115. if Rt2 <> 0 then
  2116. Rt2 := 1 / Sx
  2117. else
  2118. Rt2 := 0.00000001;
  2119. Rt2 := Rt2 * 2 * Pi;
  2120. Rr := Sy;
  2121. if Rr <> 0 then
  2122. Rr := 1 / Rr
  2123. else
  2124. Rr := 0.00000001;
  2125. Rcx := Cx;
  2126. if Rcx <> 0 then
  2127. Rcx := 1 / Rcx
  2128. else
  2129. Rcx := 0.00000001;
  2130. Rcy := Cy;
  2131. if Rcy <> 0 then
  2132. Rcy := 1 / Rcy
  2133. else
  2134. Rcy := 0.00000001;
  2135. TransformValid := True;
  2136. end;
  2137. procedure TPolarTransformation.SetDstRect(const Value: TFloatRect);
  2138. begin
  2139. FDstRect := Value;
  2140. Changed;
  2141. end;
  2142. procedure TPolarTransformation.TransformFloat(SrcX, SrcY: TFloat; out DstX,
  2143. DstY: TFloat);
  2144. var
  2145. R, Theta, S, C: TFloat;
  2146. begin
  2147. Theta := (SrcX - SrcRect.Left) * Rt2 + Phase;
  2148. R := (SrcY - SrcRect.Bottom) * Rr;
  2149. GR32_Math.SinCos(Theta, S, C);
  2150. DstX := Dx * R * C + Cx;
  2151. DstY := Dy * R * S + Cy;
  2152. end;
  2153. procedure TPolarTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
  2154. out SrcX, SrcY: TFloat);
  2155. const
  2156. PI2 = 2 * PI;
  2157. var
  2158. Dcx, Dcy, Theta: TFloat;
  2159. begin
  2160. Dcx := (DstX - Cx) * Rcx;
  2161. Dcy := (DstY - Cy) * Rcy;
  2162. Theta := ArcTan2(Dcy, Dcx) + Pi - Phase;
  2163. if Theta < 0 then
  2164. Theta := Theta + PI2;
  2165. SrcX := SrcRect.Left + Theta * Rt;
  2166. SrcY := SrcRect.Bottom - GR32_Math.Hypot(Dcx, Dcy) * Sy;
  2167. end;
  2168. procedure TPolarTransformation.SetPhase(const Value: TFloat);
  2169. begin
  2170. FPhase := Value;
  2171. Changed;
  2172. end;
  2173. //------------------------------------------------------------------------------
  2174. //
  2175. // TPathTransformation
  2176. //
  2177. //------------------------------------------------------------------------------
  2178. destructor TPathTransformation.Destroy;
  2179. begin
  2180. FTopHypot := nil;
  2181. FBottomHypot := nil;
  2182. inherited;
  2183. end;
  2184. procedure TPathTransformation.PrepareTransform;
  2185. var
  2186. I: Integer;
  2187. L, DDist: TFloat;
  2188. begin
  2189. if not (Assigned(FTopCurve) and Assigned(FBottomCurve)) then
  2190. raise ETransformError.Create(RCStrTopBottomCurveNil);
  2191. SetLength(FTopHypot, Length(FTopCurve));
  2192. SetLength(FBottomHypot, Length(FBottomCurve));
  2193. L := 0;
  2194. for I := 0 to High(FTopCurve) - 1 do
  2195. begin
  2196. FTopHypot[I].Dist := L;
  2197. with FTopCurve[I + 1] do
  2198. L := L + GR32_Math.Hypot(FTopCurve[I].X - X, FTopCurve[I].Y - Y);
  2199. end;
  2200. FTopLength := L;
  2201. for I := 1 to High(FTopCurve) do
  2202. with FTopHypot[I] do
  2203. begin
  2204. DDist := Dist - FTopHypot[I - 1].Dist;
  2205. if DDist <> 0 then
  2206. RecDist := 1 / DDist
  2207. else
  2208. if I > 1 then
  2209. RecDist := FTopHypot[I - 1].RecDist
  2210. else
  2211. RecDist := 0;
  2212. end;
  2213. L := 0;
  2214. for I := 0 to High(FBottomCurve) - 1 do
  2215. begin
  2216. FBottomHypot[I].Dist := L;
  2217. with FBottomCurve[I + 1] do
  2218. L := L + GR32_Math.Hypot(FBottomCurve[I].X - X, FBottomCurve[I].Y - Y);
  2219. end;
  2220. FBottomLength := L;
  2221. for I := 1 to High(FBottomCurve) do
  2222. with FBottomHypot[I] do
  2223. begin
  2224. DDist := Dist - FBottomHypot[I - 1].Dist;
  2225. if DDist <> 0 then
  2226. RecDist := 1 / DDist
  2227. else
  2228. if I > 1 then
  2229. RecDist := FBottomHypot[I - 1].RecDist
  2230. else
  2231. RecDist := 0;
  2232. end;
  2233. rdx := 1 / (SrcRect.Right - SrcRect.Left);
  2234. rdy := 1 / (SrcRect.Bottom - SrcRect.Top);
  2235. TransformValid := True;
  2236. end;
  2237. procedure TPathTransformation.SetBottomCurve(const Value: TArrayOfFloatPoint);
  2238. begin
  2239. FBottomCurve := Value;
  2240. Changed;
  2241. end;
  2242. procedure TPathTransformation.SetTopCurve(const Value: TArrayOfFloatPoint);
  2243. begin
  2244. FTopCurve := Value;
  2245. Changed;
  2246. end;
  2247. procedure TPathTransformation.TransformFloat(SrcX, SrcY: TFloat; out DstX,
  2248. DstY: TFloat);
  2249. var
  2250. I, H: Integer;
  2251. X, Y, fx, dx, dy, r, Tx, Ty, Bx, By: TFloat;
  2252. begin
  2253. X := (SrcX - SrcRect.Left) * rdx;
  2254. Y := (SrcY - SrcRect.Top) * rdy;
  2255. fx := X * FTopLength;
  2256. I := 1;
  2257. H := High(FTopHypot);
  2258. while (FTopHypot[I].Dist < fx) and (I < H) do
  2259. Inc(I);
  2260. with FTopHypot[I] do
  2261. r := (Dist - fx) * RecDist;
  2262. dx := (FTopCurve[I - 1].X - FTopCurve[I].X);
  2263. dy := (FTopCurve[I - 1].Y - FTopCurve[I].Y);
  2264. Tx := FTopCurve[I].X + r * dx;
  2265. Ty := FTopCurve[I].Y + r * dy;
  2266. fx := X * FBottomLength;
  2267. I := 1;
  2268. H := High(FBottomHypot);
  2269. while (FBottomHypot[I].Dist < fx) and (I < H) do
  2270. Inc(I);
  2271. with FBottomHypot[I] do
  2272. r := (Dist - fx) * RecDist;
  2273. dx := (FBottomCurve[I - 1].X - FBottomCurve[I].X);
  2274. dy := (FBottomCurve[I - 1].Y - FBottomCurve[I].Y);
  2275. Bx := FBottomCurve[I].X + r * dx;
  2276. By := FBottomCurve[I].Y + r * dy;
  2277. DstX := Tx + Y * (Bx - Tx);
  2278. DstY := Ty + Y * (By - Ty);
  2279. end;
  2280. //------------------------------------------------------------------------------
  2281. //
  2282. // TDisturbanceTransformation
  2283. //
  2284. //------------------------------------------------------------------------------
  2285. function TDisturbanceTransformation.GetTransformedBounds(
  2286. const ASrcRect: TFloatRect): TFloatRect;
  2287. begin
  2288. Result := ASrcRect;
  2289. GR32.InflateRect(Result, 0.5 * FDisturbance, 0.5 * FDisturbance);
  2290. end;
  2291. procedure TDisturbanceTransformation.ReverseTransformFloat(DstX,
  2292. DstY: TFloat; out SrcX, SrcY: TFloat);
  2293. begin
  2294. SrcX := DstX + (Random - 0.5) * FDisturbance;
  2295. SrcY := DstY + (Random - 0.5) * FDisturbance;
  2296. end;
  2297. procedure TDisturbanceTransformation.SetDisturbance(const Value: TFloat);
  2298. begin
  2299. FDisturbance := Value;
  2300. Changed;
  2301. end;
  2302. //------------------------------------------------------------------------------
  2303. //
  2304. // TRadialDistortionTransformation
  2305. //
  2306. //------------------------------------------------------------------------------
  2307. constructor TRadialDistortionTransformation.Create;
  2308. begin
  2309. FCoefficient1 := 0;
  2310. FCoefficient2 := 0;
  2311. FScale := 1;
  2312. FMapElements := 0;
  2313. end;
  2314. function TRadialDistortionTransformation.HasTransformedBounds: Boolean;
  2315. begin
  2316. Result := False;
  2317. end;
  2318. procedure TRadialDistortionTransformation.PrepareReverseMap;
  2319. var
  2320. i, j, LowerI, UpperI, jmax: Integer;
  2321. r_src, r_tgt, LowerValue, UpperValue: TFloat;
  2322. {$if defined(MSWINDOWS) and defined(DEBUG)}
  2323. // some counters to evaluate the mapping
  2324. interpolated, unset, mapToSameIndex, IndexOutOfRange: Integer;
  2325. {$ifend}
  2326. begin
  2327. if MapElements <= 1 then
  2328. MapElements := Trunc(r_0);
  2329. r_tgt_max := 2;
  2330. r_tgt_min := -0.5;
  2331. SetLength(Map, MapElements);
  2332. for i := 0 to High(Map) do
  2333. Map[i] := -1;
  2334. jmax := 1000;
  2335. {$if defined(MSWINDOWS) and defined(DEBUG)}
  2336. mapToSameIndex := 0;
  2337. IndexOutOfRange := 0;
  2338. {$ifend}
  2339. for j := 0 to jmax do
  2340. begin
  2341. r_src := j/jmax*2;
  2342. r_tgt := Scale*(1 + FCoefficient1 * Sqr(r_src) + FCoefficient2 * Power(r_src, 4));
  2343. Assert(InRange(r_tgt, r_tgt_min, r_tgt_max));
  2344. i := Trunc((r_tgt*r_src-r_tgt_min)/(r_tgt_max-r_tgt_min)*(High(Map)-1));
  2345. if not InRange(i, 0, High(Map)) then
  2346. begin
  2347. {$if defined(MSWINDOWS) and defined(DEBUG)}
  2348. Inc(IndexOutOfRange);
  2349. // OutputDebugString(PChar(Format('PrepareReverseMap: i=%d out of range (0, MapElements=%d), r_tgt=%f', [ i, MapElements, r_tgt ])))
  2350. {$ifend}
  2351. end
  2352. else
  2353. if Map[i]<>-1 then
  2354. begin
  2355. {$if defined(MSWINDOWS) and defined(DEBUG)}
  2356. Inc(mapToSameIndex);
  2357. // OutputDebugString(PChar(Format('PrepareReverseMap: Map[i=%d] already has value %f (wanted to put %f there)', [ i, Map[i], r_tgt ])))
  2358. {$ifend}
  2359. end
  2360. else
  2361. Map[i] := r_tgt;
  2362. end;
  2363. {$if defined(MSWINDOWS) and defined(DEBUG)}
  2364. unset := 0;
  2365. for i := 0 to High(Map) do
  2366. begin
  2367. if Map[i] = -1 then
  2368. Inc(unset);
  2369. end;
  2370. {$ifend}
  2371. // linear interpolation where Map[i] == -1 (but no extrapolation)
  2372. i := 0;
  2373. LowerI := -1;
  2374. LowerValue := -1;
  2375. {$if defined(MSWINDOWS) and defined(DEBUG)}
  2376. interpolated := 0;
  2377. {$ifend}
  2378. repeat
  2379. if Map[i] = -1 then
  2380. begin
  2381. if LowerI <> -1 then
  2382. begin
  2383. UpperI := i+1;
  2384. while (UpperI<=High(Map)) and (Map[UpperI] = -1) do
  2385. Inc(UpperI);
  2386. if UpperI<=High(Map) then
  2387. begin
  2388. UpperValue := Map[UpperI];
  2389. for j := LowerI+1 to UpperI-1 do
  2390. begin
  2391. Map[j] := LowerValue + (UpperValue-LowerValue) * (j-LowerI) / (UpperI - LowerI);
  2392. {$if defined(MSWINDOWS) and defined(DEBUG)}
  2393. Inc(interpolated);
  2394. {$ifend}
  2395. end;
  2396. end;
  2397. end;
  2398. end
  2399. else
  2400. begin
  2401. LowerI := i;
  2402. LowerValue := Map[i];
  2403. end;
  2404. Inc(i);
  2405. until i > High(Map);
  2406. {$if defined(MSWINDOWS) and defined(DEBUG)}
  2407. OutputDebugString(PChar(Format(
  2408. 'TRadialDistortionTransformation.PrepareReverseMap: mapToSameIndex=%d. IndexOutOfRange=%d. %d out of %d map elements were uninitialized, %d of these were interpolated',
  2409. [ mapToSameIndex, IndexOutOfRange, unset, High(Map), interpolated ])));
  2410. {$ifend}
  2411. for i := 0 to High(Map) do
  2412. begin
  2413. if Map[i] = -1 then
  2414. Map[i] := 1;
  2415. end;
  2416. {$if defined(MSWINDOWS) and defined(DEBUG)}
  2417. OutputDebugString(PChar(Format('TRadialDistortionTransformation.PrepareReverseMap: MinValue(Map)=%f MaxValue(Map)=%f', [ MinValue(Map), MaxValue(Map) ])));
  2418. {$ifend}
  2419. end;
  2420. procedure TRadialDistortionTransformation.PrepareTransform;
  2421. var
  2422. r: TRect;
  2423. begin
  2424. if GR32.IsRectEmpty(SrcRect) then
  2425. raise Exception.Create(RCStrSrcRectIsEmpty);
  2426. TransformValid := not GR32.IsRectEmpty(SrcRect);
  2427. if Not TransformValid then
  2428. Exit;
  2429. // center / focal point relative to which all (un)distortions are calculated
  2430. FFocalPoint.x := (SrcRect.Right + SrcRect.Left) / 2;
  2431. FFocalPoint.y := (SrcRect.Bottom + SrcRect.Top) / 2;
  2432. r := MakeRect(SrcRect);
  2433. r_0 := Sqrt(2*Sqr(Min(r.Right - r.Left, r.Bottom - r.Top)))/2;
  2434. PrepareReverseMap;
  2435. end;
  2436. function TRadialDistortionTransformation.LookUpReverseMap(const r_tgt: TFloat): TFloat;
  2437. var
  2438. index: Integer;
  2439. begin
  2440. index := Trunc((r_tgt-r_tgt_min) / (r_tgt_max-r_tgt_min) * High(Map));
  2441. if not InRange(index, 0, High(Map)) then
  2442. raise Exception.Create(Format('TRadialDistortionTransformation.LookUpReverseMap: Index %d out of range (0..%d)', [ index, MapElements ]));
  2443. Result := Map[index];
  2444. end;
  2445. procedure TRadialDistortionTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
  2446. out SrcX, SrcY: TFloat);
  2447. var
  2448. r_tgt, r_src: Single;
  2449. d: TFloatPoint;
  2450. begin
  2451. d.x := DstX;
  2452. d.y := DstY;
  2453. r_tgt := Distance(FFocalPoint, d)/r_0;
  2454. r_src := LookUpReverseMap(r_tgt);
  2455. SrcX := FFocalPoint.X + (d.X-FFocalPoint.X) / r_src;
  2456. SrcY := FFocalPoint.Y + (d.Y-FFocalPoint.Y) / r_src;
  2457. end;
  2458. procedure TRadialDistortionTransformation.SetCoefficient1(const Value: TFloat);
  2459. begin
  2460. FCoefficient1 := Value;
  2461. Changed;
  2462. end;
  2463. procedure TRadialDistortionTransformation.SetCoefficient2(const Value: TFloat);
  2464. begin
  2465. FCoefficient2 := Value;
  2466. Changed;
  2467. end;
  2468. procedure TRadialDistortionTransformation.SetScale(const Value: TFloat);
  2469. begin
  2470. FScale := Value;
  2471. Changed;
  2472. end;
  2473. procedure TRadialDistortionTransformation.SetMapElements(const Value: Integer);
  2474. begin
  2475. FMapElements := Value;
  2476. Changed;
  2477. end;
  2478. procedure TRadialDistortionTransformation.TransformFloat(SrcX, SrcY: TFloat; out DstX, DstY: TFloat);
  2479. var
  2480. r_tgt, r_src: Single;
  2481. d: TFloatPoint;
  2482. begin
  2483. d.x := SrcX;
  2484. d.y := SrcY;
  2485. r_src := Distance(FFocalPoint, d)/r_0;
  2486. r_tgt := Scale*(1 + FCoefficient1 * Sqr(r_src) + FCoefficient2 * Power(r_src, 4));
  2487. DstX := FFocalPoint.X + (d.X-FFocalPoint.X) * r_tgt;
  2488. DstY := FFocalPoint.Y + (d.Y-FFocalPoint.Y) * r_tgt;
  2489. end;
  2490. //------------------------------------------------------------------------------
  2491. //
  2492. // TRemapTransformation
  2493. //
  2494. //------------------------------------------------------------------------------
  2495. constructor TRemapTransformation.Create;
  2496. begin
  2497. inherited;
  2498. FScalingFixed := FixedPoint(1, 1);
  2499. FScalingFloat := FloatPoint(1, 1);
  2500. FOffset := FloatPoint(0,0);
  2501. FVectorMap := TVectorMap.Create;
  2502. // Ensuring initial setup to avoid exceptions
  2503. FVectorMap.SetSize(1, 1);
  2504. end;
  2505. destructor TRemapTransformation.Destroy;
  2506. begin
  2507. FVectorMap.Free;
  2508. inherited;
  2509. end;
  2510. //------------------------------------------------------------------------------
  2511. function TRemapTransformation.GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect;
  2512. const
  2513. InfRect: TFloatRect = (Left: -Infinity; Top: -Infinity; Right: Infinity; Bottom: Infinity);
  2514. begin
  2515. // We can't predict the ultimate bounds without transforming each vector in
  2516. // the vector map, return the absolute biggest possible transformation bounds
  2517. Result := InfRect;
  2518. end;
  2519. function TRemapTransformation.HasTransformedBounds: Boolean;
  2520. begin
  2521. Result := False;
  2522. end;
  2523. procedure TRemapTransformation.PrepareTransform;
  2524. begin
  2525. if GR32.IsRectEmpty(SrcRect) then
  2526. raise Exception.Create(RCStrSrcRectIsEmpty);
  2527. if GR32.IsRectEmpty(FMappingRect) then
  2528. raise Exception.Create(RCStrMappingRectIsEmpty);
  2529. with SrcRect do
  2530. begin
  2531. FSrcTranslationFloat.X := Left;
  2532. FSrcTranslationFloat.Y := Top;
  2533. FSrcScaleFloat.X := (Right - Left) / (FVectorMap.Width - 1);
  2534. FSrcScaleFloat.Y := (Bottom - Top) / (FVectorMap.Height - 1);
  2535. FSrcTranslationFixed := FixedPoint(FSrcTranslationFloat);
  2536. FSrcScaleFixed := FixedPoint(FSrcScaleFloat);
  2537. end;
  2538. with FMappingRect do
  2539. begin
  2540. FDstTranslationFloat.X := Left;
  2541. FDstTranslationFloat.Y := Top;
  2542. FDstScaleFloat.X := (FVectorMap.Width - 1) / (Right - Left);
  2543. FDstScaleFloat.Y := (FVectorMap.Height - 1) / (Bottom - Top);
  2544. FCombinedScalingFloat.X := FDstScaleFloat.X * FScalingFloat.X;
  2545. FCombinedScalingFloat.Y := FDstScaleFloat.Y * FScalingFloat.Y;
  2546. FCombinedScalingFixed := FixedPoint(FCombinedScalingFloat);
  2547. FDstTranslationFixed := FixedPoint(FDstTranslationFloat);
  2548. FDstScaleFixed := FixedPoint(FDstScaleFloat);
  2549. end;
  2550. TransformValid := True;
  2551. end;
  2552. procedure TRemapTransformation.ReverseTransformFixed(DstX, DstY: TFixed;
  2553. out SrcX, SrcY: TFixed);
  2554. begin
  2555. with FVectorMap.FixedVectorX[DstX - FOffsetFixed.X, DstY - FOffsetFixed.Y] do
  2556. begin
  2557. DstX := DstX - FDstTranslationFixed.X;
  2558. DstX := FixedMul(DstX , FDstScaleFixed.X);
  2559. DstX := DstX + FixedMul(X, FCombinedScalingFixed.X);
  2560. DstX := FixedMul(DstX, FSrcScaleFixed.X);
  2561. SrcX := DstX + FSrcTranslationFixed.X;
  2562. DstY := DstY - FDstTranslationFixed.Y;
  2563. DstY := FixedMul(DstY, FDstScaleFixed.Y);
  2564. DstY := DstY + FixedMul(Y, FCombinedScalingFixed.Y);
  2565. DstY := FixedMul(DstY, FSrcScaleFixed.Y);
  2566. SrcY := DstY + FSrcTranslationFixed.Y;
  2567. end;
  2568. end;
  2569. procedure TRemapTransformation.ReverseTransformFloat(DstX, DstY: TFloat;
  2570. out SrcX, SrcY: TFloat);
  2571. begin
  2572. with FVectorMap.FloatVectorF[DstX - FOffset.X, DstY - FOffset.Y] do
  2573. begin
  2574. DstX := DstX - FDstTranslationFloat.X;
  2575. DstY := DstY - FDstTranslationFloat.Y;
  2576. DstX := DstX * FDstScaleFloat.X;
  2577. DstY := DstY * FDstScaleFloat.Y;
  2578. DstX := DstX + X * FCombinedScalingFloat.X;
  2579. DstY := DstY + Y * FCombinedScalingFloat.Y;
  2580. DstX := DstX * FSrcScaleFloat.X;
  2581. DstY := DstY * FSrcScaleFloat.Y;
  2582. SrcX := DstX + FSrcTranslationFloat.X;
  2583. SrcY := DstY + FSrcTranslationFloat.Y;
  2584. end;
  2585. end;
  2586. procedure TRemapTransformation.ReverseTransformInt(DstX, DstY: Integer;
  2587. out SrcX, SrcY: Integer);
  2588. begin
  2589. with FVectorMap.FixedVector[DstX - FOffsetInt.X, DstY - FOffsetInt.Y] do
  2590. begin
  2591. DstX := DstX * FixedOne - FDstTranslationFixed.X;
  2592. DstY := DstY * FixedOne - FDstTranslationFixed.Y;
  2593. DstX := FixedMul(DstX, FDstScaleFixed.X);
  2594. DstY := FixedMul(DstY, FDstScaleFixed.Y);
  2595. DstX := DstX + FixedMul(X, FCombinedScalingFixed.X);
  2596. DstY := DstY + FixedMul(Y, FCombinedScalingFixed.Y);
  2597. DstX := FixedMul(DstX, FSrcScaleFixed.X);
  2598. DstY := FixedMul(DstY, FSrcScaleFixed.Y);
  2599. SrcX := FixedRound(DstX + FSrcTranslationFixed.X);
  2600. SrcY := FixedRound(DstY + FSrcTranslationFixed.Y);
  2601. end;
  2602. end;
  2603. procedure TRemapTransformation.Scale(Sx, Sy: TFloat);
  2604. begin
  2605. FScalingFixed.X := Fixed(Sx);
  2606. FScalingFixed.Y := Fixed(Sy);
  2607. FScalingFloat.X := Sx;
  2608. FScalingFloat.Y := Sy;
  2609. Changed;
  2610. end;
  2611. procedure TRemapTransformation.SetMappingRect(Rect: TFloatRect);
  2612. begin
  2613. FMappingRect := Rect;
  2614. Changed;
  2615. end;
  2616. procedure TRemapTransformation.SetOffset(const Value: TFloatVector);
  2617. begin
  2618. FOffset := Value;
  2619. FOffsetInt := Point(Value);
  2620. FOffsetFixed := FixedPoint(Value);
  2621. Changed;
  2622. end;
  2623. //------------------------------------------------------------------------------
  2624. //
  2625. // TSphereTransformation
  2626. //
  2627. //------------------------------------------------------------------------------
  2628. //------------------------------------------------------------------------------
  2629. // Utilities
  2630. //------------------------------------------------------------------------------
  2631. procedure Modulo2Pi(var Angle: TFloat); {Result is between 0 and 2PI }
  2632. {$if defined(PUREPASCAL) or (not defined(TARGET_x86))}
  2633. begin
  2634. Angle := GR32_Math.FloatMod(Angle, PI*2);
  2635. end;
  2636. {$else}
  2637. asm
  2638. FLDPI
  2639. FADD ST,ST // 2PI
  2640. FLD DWORD ptr [Angle]
  2641. FPREM // calc Modulo
  2642. FLDZ
  2643. FCOMIP ST,ST(1) // Compare 0 and Modulo (+pop 0)
  2644. JNB @@1 // if Modulo >= 0 then
  2645. FSTP DWORD ptr [Angle] // return Modulo...
  2646. FSTP ST(0) // POP the rest (2PI)
  2647. JMP @@2
  2648. @@1: FADDP // add Modulo and Rest (2PI)
  2649. FSTP DWORD ptr [Angle] // Modulo+2PI...
  2650. @@2: FWAIT
  2651. end;
  2652. {$ifend}
  2653. constructor TSphereTransformation.Create;
  2654. begin
  2655. inherited;
  2656. FRadius := 1;
  2657. end;
  2658. //------------------------------------------------------------------------------
  2659. function TSphereTransformation.GetTransformedBounds(const ASrcRect: TFloatRect): TFloatRect;
  2660. begin
  2661. // There is not direct relation between SourceRect and DestRect !
  2662. // During transformation process this rect will be clipped.
  2663. Result.Left := FCenter.X - FRadius;
  2664. Result.Top := FCenter.Y - FRadius;
  2665. Result.Bottom := FCenter.Y + FRadius;
  2666. Result.Right := FCenter.X + FRadius;
  2667. end;
  2668. function TSphereTransformation.HasTransformedBounds: Boolean;
  2669. begin
  2670. Result := False;
  2671. end;
  2672. function TSphereTransformation.IsInSphere(CartesianX, CartesianY: TFloat): boolean;
  2673. begin
  2674. if not TransformValid then
  2675. PrepareTransform;
  2676. CartesianX := CartesianX - FCenter.X;
  2677. CartesianY := CartesianY - FCenter.Y;
  2678. Result := (FSquareRadius >= (CartesianX * CartesianX + CartesianY * CartesianY));
  2679. end;
  2680. procedure TSphereTransformation.PrepareTransform;
  2681. begin
  2682. // Invariants during transformation
  2683. FMapWidth := (SrcRect.Width - 1) / (2 * PI);
  2684. FMapHeight := (SrcRect.Height - 1) / PI;
  2685. FSquareRadius := Sqr(FRadius);
  2686. GR32_Math.SinCos(FLattitude, FLattitudeSin, FLattitudeCos);
  2687. FLattitudeSinInvRadius := -FLattitudeSin / FRadius;
  2688. FLattitudeCosInvRadius := FLattitudeCos / FRadius;
  2689. FSrcRectTop := SrcRect.Top;
  2690. FSrcRectLeft := SrcRect.Left;
  2691. TransformValid := True;
  2692. end;
  2693. procedure TSphereTransformation.ReverseTransformFloat(DstX, DstY: TFloat; out SrcX, SrcY: TFloat);
  2694. // FPC currently refuses to compile the ASM version.
  2695. // Consider deprecating it as it's not really worth the effort - or replace it with a SSE version
  2696. {$if defined(PUREPASCAL) or (not defined(TARGET_x86)) or (defined(FPC))}
  2697. var
  2698. Dist: TFloat;
  2699. begin
  2700. // Screen projection on sphere
  2701. DstX := DstX - FCenter.X; // = Y
  2702. DstY := FCenter.Y - DstY; // = Z
  2703. Dist := DstX * DstX + DstY * DstY;
  2704. if (Dist > FSquareRadius) then // Not projectable on the sphere
  2705. begin
  2706. SrcX := -1;
  2707. SrcY := -1;
  2708. Exit;
  2709. end;
  2710. Dist := Sqrt(FSquareRadius - Dist);
  2711. // Apply rotations
  2712. DstX := Arctan2(DstX, Dist * FLattitudeCos + DstY * FLattitudeSin) + FLongitude;
  2713. Modulo2Pi(DstX);
  2714. // Map projection
  2715. SrcX := SrcRect.Left + DstX * FMapWidth;
  2716. SrcY := SrcRect.Top + ArcCos(DstY * FLattitudeCosInvRadius + Dist * FLattitudeSinInvRadius) * FMapHeight;
  2717. end;
  2718. {$else}
  2719. {Assembler version (FPU) ... 4% faster on a P4 }
  2720. asm
  2721. // screen projection on sphere
  2722. // DstX := DstX - FCenterX; // = Y
  2723. fld DstX // DstX
  2724. fsub [eax].FCenter.X // DstX'
  2725. // DstY := FCenterY - DstY; // = Z
  2726. fld [eax].FCenter.Y // FCenterY | DstX'
  2727. fsub DstY // DstY' | DstX'
  2728. // x := DstX * DstX + DstY * DstY;
  2729. fld st(0) // Z | Z | Y
  2730. fmul st(0),st(1) // ZZ | Z | Y
  2731. fld st(2) // Y | ZZ | Z | Y
  2732. fmul st(0),st(3)
  2733. faddp // X' | Z | Y
  2734. // if (FSquareRadius < x) then // not projetable in the sphere.
  2735. fld [eax].FSquareRadius
  2736. fcomi st(0),st(1) // st(0) < st(1)
  2737. jnbe @@1
  2738. fstp st(0)
  2739. fstp st(0)
  2740. fstp st(0)
  2741. fstp st(0)
  2742. // SrcX := -1;
  2743. mov [SrcX],$bf800000
  2744. // SrcY := -1;
  2745. mov [SrcY],$bf800000
  2746. // Exit;
  2747. jmp @@fin
  2748. @@1:
  2749. // x := sqrt(FSquareRadius - x);
  2750. fsubrp
  2751. fsqrt // X | Z | Y
  2752. // apply rotations
  2753. // DstX := Arctan2(Y,X * FLattitudeCos + Z * FLattitudeSin) + FLongitude; // Lon
  2754. fxch st(2) // Y | Z | Y
  2755. fld st(2) // X | Y | Z | X
  2756. fmul [eax].FLattitudeCos
  2757. fld st(2) // Z | Xx. | Y | Z | X
  2758. fmul [eax].FLattitudeSin // Zx. | Xx. | Y | Z | X
  2759. faddp // Xx+Zx | Y | Z | X
  2760. fpatan
  2761. fadd [eax].FLongitude // DstX | Z | X
  2762. // if DstX > PI2S then
  2763. fldpi
  2764. fadd st(0),st(0) // 2PI | DstX | Z | X
  2765. fcomi st(0),st(1) // st(0) < st(1)
  2766. jnb @@test2
  2767. // DstX := DstX - PI2S
  2768. fsubp st(1),st(0)
  2769. jmp @@testfin
  2770. // else if DstX < 0 then
  2771. @@test2:
  2772. fldz
  2773. fcomip st(0),st(2) // st(0) < st(2)
  2774. jb @@test3
  2775. // DstX := DstX + PI2S;
  2776. faddp
  2777. jmp @@testfin
  2778. @@test3:
  2779. fstp st(0)
  2780. @@testfin:
  2781. // Map projection
  2782. // SrcX := DstX * FMapWidth;
  2783. fmul [eax].FMapWidth
  2784. FADD [eax].FSrcRectLeft
  2785. fstp dword ptr [SrcX]// Z | X
  2786. // SrcY := ArcCos(Z * FLattitudeCosInvRadius + x * FLattitudeSinInvRadius) * FMapHeight;
  2787. fmul [eax].FLattitudeCosInvRadius
  2788. fxch
  2789. fmul [eax].FLattitudeSinInvRadius
  2790. faddp
  2791. FLD1 // 1 | X
  2792. FLD ST(1) // X | 1 | X
  2793. FMUL ST(0),ST(0) // X² | 1 | X
  2794. FSUBP ST(1),ST(0) // 1 - X² | X
  2795. FABS //<- avoid rounding errors...
  2796. FSQRT // sqrt(.)| X
  2797. FXCH st(1)
  2798. FPATAN // result |
  2799. fmul [eax].FMapHeight
  2800. FADD [eax].FSrcRectTop
  2801. fstp dword ptr [SrcY]
  2802. @@fin:
  2803. fwait
  2804. end;
  2805. {$ifend}
  2806. function TSphereTransformation.ScreenCoordinate(var X, Y: TFloat): boolean;
  2807. var
  2808. SinLong, CosLong, SinLat, CosLat: TFloat;
  2809. begin
  2810. if not TransformValid then
  2811. PrepareTransform;
  2812. GR32_Math.SinCos(X - FLongitude, SinLong, CosLong);
  2813. GR32_Math.SinCos(Y, SinLat, CosLat);
  2814. Result := (SinLat * CosLong * FLattitudeCos >= CosLat * FLattitudeSin);
  2815. if Result then
  2816. begin
  2817. X := FCenter.X + FRadius * SinLat * SinLong;
  2818. Y := FCenter.Y - FRadius * (SinLat * CosLong * FLattitudeSin + CosLat * FLattitudeCos);
  2819. end;
  2820. end;
  2821. procedure TSphereTransformation.SetCenter(const Value: TFloatPoint);
  2822. begin
  2823. if FCenter <> Value then
  2824. begin
  2825. FCenter := Value;
  2826. Changed;
  2827. end;
  2828. end;
  2829. procedure TSphereTransformation.SetLattitude(const Value: TFloat);
  2830. begin
  2831. if FLattitude <> Value then
  2832. begin
  2833. FLattitude := Value;
  2834. Modulo2Pi(FLattitude);
  2835. Changed;
  2836. end;
  2837. end;
  2838. procedure TSphereTransformation.SetLongitude(const Value: TFloat);
  2839. begin
  2840. if FLongitude <> Value then
  2841. begin
  2842. FLongitude := Value;
  2843. Modulo2Pi(FLongitude);
  2844. Changed;
  2845. end;
  2846. end;
  2847. procedure TSphereTransformation.SetRadius(const Value: TFloat);
  2848. begin
  2849. if (Value > 0) and (FRadius <> Value) then
  2850. begin
  2851. FRadius := Value;
  2852. Changed;
  2853. end;
  2854. end;
  2855. function TSphereTransformation.SphericalCoordinate(CartesianX, CartesianY: TFloat): TFloatPoint;
  2856. var
  2857. Dist: TFloat;
  2858. begin
  2859. if not TransformValid then
  2860. PrepareTransform;
  2861. // Screen projection on sphere
  2862. CartesianX := CartesianX - FCenter.X; // = Y
  2863. CartesianY := FCenter.Y - CartesianY; // = Z
  2864. Dist := CartesianX * CartesianX + CartesianY * CartesianY;
  2865. if (Dist > FSquareRadius) then // Not projectable in the sphere.
  2866. begin
  2867. Result.X := 0;
  2868. Result.Y := 0;
  2869. Exit;
  2870. end;
  2871. Dist := Sqrt(FSquareRadius - Dist);
  2872. // Apply rotations
  2873. Result.X := Arctan2(CartesianX, Dist * FLattitudeCos + CartesianY * FLattitudeSin) + FLongitude;
  2874. Modulo2Pi(Result.X);
  2875. Result.Y := ArcCos(CartesianY * FLattitudeCosInvRadius + Dist * FLattitudeSinInvRadius) - (PI / 2);
  2876. end;
  2877. //------------------------------------------------------------------------------
  2878. //
  2879. // Bindings
  2880. //
  2881. //------------------------------------------------------------------------------
  2882. var
  2883. TransformsRegistry: TFunctionRegistry;
  2884. procedure RegisterBindings;
  2885. begin
  2886. TransformsRegistry := NewRegistry('GR32_Transforms bindings');
  2887. TransformsRegistry.RegisterBinding(@@DET_2x2_32, 'DET_2x2_32');
  2888. TransformsRegistry.RegisterBinding(@@DET_3x3_32, 'DET_3x3_32');
  2889. TransformsRegistry.RegisterBinding(@@DET_2x2_64, 'DET_2x2_64');
  2890. // DET_2x2_32
  2891. TransformsRegistry[@@DET_2x2_32].Add(@DET_2x2_32_Pas, [isPascal]).Name := 'DET_2x2_32_Pas';
  2892. {$IFNDEF PUREPASCAL}
  2893. {$if defined(TARGET_x86)}
  2894. TransformsRegistry[@@DET_2x2_32].Add(@DET_2x2_32_ASM, [isAssembler]).Name := 'DET_2x2_32_ASM';
  2895. {$elseif defined(TARGET_x64) and (not defined(OMIT_SSE2))}
  2896. TransformsRegistry[@@DET_2x2_32].Add(@DET_2x2_32_SSE, [isSSE]).Name := 'DET_2x2_32_SSE';
  2897. {$ifend}
  2898. {$ENDIF}
  2899. // DET_2x2_64
  2900. TransformsRegistry[@@DET_2x2_64].Add(@DET_2x2_64_Pas, [isPascal]).Name := 'DET_2x2_64_Pas';
  2901. {$IFNDEF PUREPASCAL}
  2902. {$if defined(TARGET_x86)}
  2903. TransformsRegistry[@@DET_2x2_64].Add(@DET_2x2_64_ASM, [isAssembler]).Name := 'DET_2x2_64_ASM';
  2904. {$elseif defined(TARGET_x64) and (not defined(OMIT_SSE2))}
  2905. TransformsRegistry[@@DET_2x2_64].Add(@DET_2x2_64_SSE, [isSSE]).Name := 'DET_2x2_64_SSE';
  2906. {$ifend}
  2907. {$ENDIF}
  2908. // DET_3x3_32
  2909. TransformsRegistry[@@DET_3x3_32].Add(@DET_3x3_32_Pas, [isPascal]).Name := 'DET_3x3_32_Pas';
  2910. TransformsRegistry.RebindAll;
  2911. end;
  2912. //------------------------------------------------------------------------------
  2913. initialization
  2914. RegisterBindings;
  2915. end.